практикум по Linux Kernel

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

Модератор: Olej

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 10 мар 2015, 23:39

Olej писал(а): Вам не говорили, что код вашего модуля ядра может читать и писать файлы на диске?
Сейчас глянем как это происходит...
Поехали дальше...

Задача (*): Пусть модуль читает при загрузке из конфигурационного файла произвольное число каналов данных, каждый из которых записан конфигурационной строкой вида chan=dev123, где dev123 — это будет имя устройства /dev/dev123, в которое можно писать данные произвольной длины, а потом читать оттуда записанное.

Подсказка: Используйте код ранее сформулированной задачи (см. ранее), о записи-чтении данных произвольной длины в устройство (циклический кольцевой буфер), пример queue.tgz.

Я не буду здесь выписывать код - он достаточно объёмный ... почему и задача отмечена (*), но всё есть в архиве.
А выглядит это как-то так:

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

bash-4.2$ sudo insmod confm.ko file=/etc/xxx.cfg debug=1
bash-4.2$ ls -l /dev/x*
crw-rw-rw- 1 root root 10, 58 мар 10 21:35 /dev/x123
crw-rw-rw- 1 root root 10, 57 мар 10 21:35 /dev/xx456
bash-4.2$ echo 12345 > /dev/x123
bash-4.2$ cat /dev/x123
12345
bash-4.2$ echo aaaaaaaaaaaaaaaaaaaaaaaa > /dev/xx456
bash-4.2$ cat /dev/xx456
aaaaaaaaaaaaaaaaaaaaaaaa
bash-4.2$ dmesg | tail -n6
[22290.594685] + device name: /dev/x123
[22290.597053] + register device 10:56
[22290.597067] + device name: /dev/xx456
[22290.597179] + register device 10:55
[22488.283181] + deregister device 10:56
[22488.283421] + deregister device 10:55
bash-4.2$ cat /etc/confm.conf
# конфигурационный файл модуля confm.ko

chan=x123
chan = xx456
#chan= z789
Вложения
confm.tgz
(6.95 КБ) 344 скачивания

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 11 мар 2015, 09:49

Задача: Сделайте свои собственные приложения (пространство пользователя), загружающее и выгружающее, соответственно, указанный модуль ядра (так как это делают insmod и rmmod ... но только лучше ;-) ).

Эта задача описана в основном тексте (в "Расширенные возможности"), поэтому комментировать не буду.
Только обращаю внимание ... на не тривиальную задачу.
Архив всё же задублирую.
Вложения
umaster.tgz
(3.21 КБ) 351 скачивание

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 12 мар 2015, 02:26

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

Задача: Как рассмотреть все имена API, экспортируемые непосредственно ядром (не учитывая символов, экспортируемых другими динамически загруженными модулями)? Подсчитайте число таких имён в вашей системе.

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

[Olej@modules connections]$ cat /lib/modules/`uname -r`/build/Module.symvers | grep vmlinux | grep EXPORT_SYMBOL | wc -l
7522

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

[Olej@modules connections]$ cat /lib/modules/`uname -r`/build/Module.symvers | grep vmlinux | grep EXPORT_SYMBOL \
| head -n 10
0x00000000	ipv6_chk_custom_prefix	vmlinux	EXPORT_SYMBOL
0x00000000	sata_pmp_error_handler	vmlinux	EXPORT_SYMBOL_GPL
0x00000000	__cleancache_invalidate_page	vmlinux	EXPORT_SYMBOL
0x00000000	pcmcia_reset_card	vmlinux	EXPORT_SYMBOL
0x00000000	unregister_vt_notifier	vmlinux	EXPORT_SYMBOL_GPL
0x00000000	kmem_cache_alloc	vmlinux	EXPORT_SYMBOL
0x00000000	replace_page_cache_page	vmlinux	EXPORT_SYMBOL_GPL
0x00000000	__cond_resched_softirq	vmlinux	EXPORT_SYMBOL
0x00000000	set_anon_super	vmlinux	EXPORT_SYMBOL
0x00000000	rtc_class_open	vmlinux	EXPORT_SYMBOL_GPL
Здесь важно то, что из совершенно родственных вызовов (например системных вызовов), одни являются экспортируемыми, а другие нет:

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

[Olej@modules connections]$ cat /lib/modules/`uname -r`/build/Module.symvers | grep sys_open | grep EXPORT_SYMBOL
[Olej@modules connections]$ cat /lib/modules/`uname -r`/build/Module.symvers | grep sys_close | grep EXPORT_SYMBOL 
0x00000000	sys_close	vmlinux	EXPORT_SYMBOL

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 12 мар 2015, 18:33

Olej писал(а):Вот такая очень неплохая задача (вопрос), очень важная для расширенных возможностей программирования модулей:
Ещё несколько "хороших" задач (их все можно считать со *), из области расширенных возможностей программирования:

Задача: Замените один из стандартных системных вызовов Linux на свой, так, чтобы он обрабатывался вашим собственным кодом.

Задача: Расширьте один из стандартных системных вызовов Linux, так, чтобы перед выполнением системного вызова выполнялся ваш собственный кодом ... например, чтобы при выполнении open() любой программой, отчёт об этом open() ... отправлялся дяде Васе. ;-)

Задача: Сделайте то же, что в предыдущей задаче, но чтобы код вызывался не перед, а после отработки стандартного системного вызова Linux.

Задача: Добавьте новый системный вызов к стандартному набору Linux, так, чтобы только ваши приложения могли использовать возможности нового системного вызова.

Естественно, что все эти задачи - одной группы.

Я по ним не буду здесь приводить решений, потому что все эти решения есть и обсуждаются в сопроводительном тексте.
Обращаю только внимание, что они там есть.

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 12 мар 2015, 18:39

Olej писал(а): Естественно, что все эти задачи - одной группы.
А вот очень славная задача совсем из другой области:

Задача: Напишите образец собственной файловой системы используя FUSE - Filesystem in Userspace, т.е. не нишучи ни одного оператора в пространстве ядра! Ваша файловая система должна выполнять обычные заурядные операции над файловыми системами: создавать иерархии каталогов командой mkdir, создание файлов командами touch, echo (с перенаправлением), копирование cp, переименование и перемещение mv ... ну, т.е. весь джентльменский набор.
Но всё это без права писать что-либо в режиме ядра.

P.S. См. сюда: файловая система FUSE.

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

Re: практикум по Linux Kernel

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

Olej писал(а):Ещё несколько "хороших" задач (их все можно считать со *), из области расширенных возможностей программирования:
Ещё один "необъятный" класс для "хороших" задач из Linux kernel - это всё, что связано с параллельными потоками в ядре, многопроцессорностью, SMP и всё в этом духе...

Мультипроцессорность и параллелизм сами по себе одна из интереснейших и сложных тем в программировании вообще... но в kernel усугубляется тем, что:
- почти никто из широко распространённых операционных систем не предполагают параллельность внутри ядра;
- в Linux это тоже появилось не так давно, начиная с версий 2.6;
- это естественный механизм эффективного "натягивания" Linux на многоядерные SMP архитектуры (которые вскорости обещают стать много-много ядерными ;-) );
- и API для этого очень существенно отличается от подобного в пространстве приложений пользователя.

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 16 мар 2015, 02:13

Olej писал(а): Ещё один "необъятный" класс для "хороших" задач из Linux kernel - это всё, что связано с параллельными потоками в ядре, многопроцессорностью, SMP и всё в этом духе...
Задача: Для начала просто "сосчитайте" сколько процессоров присутствуют в вашей системе (архитектуре).

Предупреждение: Гипертриэдинг система Linux (или все операционные системы вообще?) не отличает от реально присутствующих 2-х процессоров. Как их различить? (я не знаю)

Такую задачу можно решать разными способами.
Вот только один из них:

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

#include <linux/module.h> 
#include <linux/init.h> 
#include <linux/smp.h>

short data_percpu[] = { 0, 0, 0, 0, 0, 0, 0 ,0 };
int size = sizeof( data_percpu ) / sizeof( data_percpu[ 0 ] );

void call_func( void* info ) {
   int cpu = get_cpu();
   if( cpu >= size ) {
      printk( KERN_INFO "CPU number %d grater %d\n", cpu, size );
      return;
   }
   data_percpu[ cpu ]++;
   put_cpu();
}

int test_nump( void ) {
   char msg[ 120 ] = ""; // = "CPU in use: "
   int i;
   on_each_cpu( call_func, NULL, 1 );
   for( i = 0; i < size; i++ )
      if( data_percpu[ i ] )
         sprintf( msg + strlen( msg ), "%d ", i );
   printk( KERN_INFO "CPU in use: %s\n", msg );
   return -1;
}

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

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

[Olej@modules tcreat]$ sudo insmod nproc.ko
insmod: ERROR: could not insert module nproc.ko: Operation not permitted
[Olej@modules tcreat]$ dmesg | tail -n1
[14061.226373] CPU in use: 0 1 2 3
Вложения
nproc.c
(797 байт) 339 скачиваний

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 16 мар 2015, 19:10

Olej писал(а): Ещё один "необъятный" класс для "хороших" задач из Linux kernel - это всё, что связано с параллельными потоками в ядре, многопроцессорностью, SMP и всё в этом духе...
Задача: Вам предстоит выполнить некоторые ординарные действия в ядре, но параллельно, средствами потоков ядра. Создайте, как минимум, 4 разных способа формирования выполнения своих действий в отдельном потоке.

Вот так ... простенько и со вкусом.

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 16 мар 2015, 19:22

Olej писал(а): Задача: Вам предстоит выполнить некоторые ординарные действия в ядре, но параллельно, средствами потоков ядра. Создайте, как минимум, 4 разных способа формирования выполнения своих действий в отдельном потоке.
1. Пользуясь старым вызовом kernel_thread().
Это тот способ, который наиболее полно описанный в литературе (рекомендуемый).

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

#include <linux/module.h> 
#include <linux/sched.h> 
#include <linux/delay.h> 

#define LOG(...) printk( KERN_INFO "! "__VA_ARGS__ )

// current - указатель на дескриптор текущей задачи 
static int threadfn( void *data ) {
   struct completion *finished = (struct completion*)data;
   LOG( "%d: start time %lX\n", current->pid, jiffies );
   msleep( 1000 );                        // пауза 1с. 
   complete( finished );                  // отмечаем факт выполнения условия
   LOG( "%d: finish time %lX\n", current->pid, jiffies );
   return 0;
}

int test_thread( void ) {
   DECLARE_COMPLETION( finished );
   unsigned long j = jiffies;
   pid_t pid;
   pid = kernel_thread( threadfn, &finished, CLONE_FS ); // запускаем новый поток
   wait_for_completion( &finished );                     // ожидаем выполнения условия 
   j = jiffies - j;
   LOG( "%d: evaluation time was %ld millisec.\n", current->pid, 1000 * j / HZ );
   return -1;
}

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

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

[olej@fedora smp]$ time sudo insmod thr1.ko
Error: could not insert module thr1.ko: Operation not permitted
real    0m1.121s
user    0m0.041s
sys     0m0.071s

[olej@fedora smp]$ dmesg | tail -n3
[ 2425.969956] ! 3080: start time 207091
[ 2426.970216] ! 3080: finish time 20747A
[ 2426.970309] ! 3079: evaluation time was 1001 millisec.
Но! ...
Этот рекомендуемый литературой способ не будет работать в поздних ядрах:

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

[Olej@modules smp]$ uname -r
3.14.8-200.fc20.i686
[Olej@modules smp]$ sudo insmod thr1.ko
[sudo] пароль для Olej:
insmod: ERROR: could not insert module thr1.ko: Unknown symbol in module
При внимательном рассмотрении это можно понять ещё при компиляции:

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

[Olej@modules smp]$ make
make -C /lib/modules/3.18.9-100.fc20.x86_64/build M=/home/Olej/2015-WORK/GlobalLogic/PRACTIS.Kernel/PRACTIS.Tasks/+TASKS/smp modules
make[1]: Вход в каталог `/usr/src/kernels/3.18.9-100.fc20.x86_64'
  CC [M]  /home/Olej/2015-WORK/GlobalLogic/PRACTIS.Kernel/PRACTIS.Tasks/+TASKS/smp/thr1.o
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "kernel_thread" [/home/Olej/2015-WORK/GlobalLogic/PRACTIS.Kernel/PRACTIS.Tasks/+TASKS/smp/thr1.ko] undefined!
  CC      /home/Olej/2015-WORK/GlobalLogic/PRACTIS.Kernel/PRACTIS.Tasks/+TASKS/smp/thr1.mod.o
  LD [M]  /home/Olej/2015-WORK/GlobalLogic/PRACTIS.Kernel/PRACTIS.Tasks/+TASKS/smp/thr1.ko
make[1]: Выход из каталога `/usr/src/kernels/3.18.9-100.fc20.x86_64'
Вон тот WARNING видите? ;-)

Подзадача: Выясните почему? Что изменилось?
Подзадача: Начиная с какой версии ядра этот способ не работает?

Причина в том, что в новых ядрах функция (имя) kernel_thread() присутствует, но не экспортируется!

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

[olej@fedora smp]$ uname -r
3.6.11-5.fc17.i686
[olej@fedora smp]$ cat /lib/modules/`uname -r`/build/Module.symvers | grep kernel_thread
0x00000000      kernel_thread   vmlinux EXPORT_SYMBOL

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

[Olej@modules tcreat]$ uname -r
3.18.9-100.fc20.x86_64
[Olej@modules smp]$ cat /lib/modules/`uname -r`/build/Module.symvers | grep kernel_thread
На 2-ю подзадачу я не знаю ответа :-? ... но в ядре 3.6 он ещё работает, а в ядре 3.14 уже нет.

При крайней нужде это можно и обойти ... как описывается в "расширенные возможности" ... но нет смысла, потому как у нас остаются другие способы.
Вложения
thr1.c
(1.14 КБ) 344 скачивания

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

Re: практикум по Linux Kernel

Непрочитанное сообщение Olej » 16 мар 2015, 19:28

Olej писал(а): Задача: Вам предстоит выполнить некоторые ординарные действия в ядре, но параллельно, средствами потоков ядра. Создайте, как минимум, 4 разных способа формирования выполнения своих действий в отдельном потоке.
2. Пользуясь новым вызовом kthread_run() (или kthread_create() ).

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

#include <linux/module.h> 
#include <linux/delay.h> 
#include <linux/kthread.h>

#define LOG(...) printk( KERN_INFO "! "__VA_ARGS__ )

// current - указатель на дескриптор текущей задачи:
static int threadfn( void *data ) {
   struct completion *finished = (struct completion*)data;
   LOG( "%d: start time %lX\n", current->pid, jiffies );
   msleep( 1000 );                        // пауза 1с. 
   complete( finished );                  // отмечаем факт выполнения условия
   LOG( "%d: finish time %lX\n", current->pid, jiffies );
   return 0;
}

int test_thread( void ) {
   DECLARE_COMPLETION( finished );
   unsigned long j = jiffies;
   struct task_struct *t = kthread_run( threadfn, &finished, "new_thread" );
   if( NULL == t ) return -EINVAL;
   wait_for_completion( &finished );      // ожидаем выполнения условия 
   j = jiffies - j;
   LOG( "%d: evaluation time was %ld millisec.\n", current->pid, 1000 * j / HZ );
   return -1;
}

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

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

[Olej@modules smp]$ time sudo insmod thr2.ko
insmod: ERROR: could not insert module thr2.ko: Operation not permitted
real    0m1.034s
user    0m0.011s
sys     0m0.014s

[Olej@modules smp]$ dmesg | tail -n3
[20298.553347] ! 13267: start time 10130F51D
[20299.554329] ! 13267: finish time 10130F906
[20299.554338] ! 13266: evaluation time was 1001 millisec.
- kthread_run() - макрос, использующий kthread_create(), поэтому вы его не обнаружите в числе экспортируемых;
- с самим kthread_create() - осторожно, потому что он создаёт поток, но его ещё не запускает ... так ваш модуль и будет висеть вечно до перезагрузки... ;-)
Вложения
thr2.c
(1.13 КБ) 340 скачиваний

Ответить

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

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

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