Библиотека сайта rus-linux.net
Цилюрик О.И. Модули ядра Linux | ||
Назад | Отладка в ядре | Вперед |
Интерфейсы пространства пользователя к модулю
Для контроля значений ключевых переменных (и даже их изменений) внутри модуля — их можно отобразить в псевдофайловые системы /proc, а ещё лучше /sys. Это часто делается, например, для счётчика обработанных в драйвере прерываний, как это показано в примере ниже (попутно показано, что таким способом можно контролировать переменные даже внутри обработчиков аппаратных прерываний):
mdsys.c :
#include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/version.h> #define SHARED_IRQ 16 // my eth0 interrupt line static int irq = SHARED_IRQ; module_param( irq, int, S_IRUGO ); // may be change static unsigned int irq_counter = 0; static irqreturn_t mdsys_interrupt( int irq, void *dev_id ) { irq_counter++; return IRQ_NONE; } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) static ssize_t show( struct class *class, struct class_attribute *attr, char *buf ) { #else static ssize_t show( struct class *class, char *buf ) { #endif sprintf( buf, "%d\n", irq_counter ); return strlen( buf ); } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) static ssize_t store( struct class *class, struct class_attribute *attr, const char *buf, size_t c #else static ssize_t store( struct class *class, const char *buf, size_t count ) { #endif int i, res = 0; const char dig[] = "0123456789"; for( i = 0; i < count; i++ ) { char *p = strchr( dig, (int)buf[ i ] ); if( NULL == p ) break; res = res * 10 + ( p - dig ); } irq_counter = res; return count; } CLASS_ATTR( mds, 0666, &show, &store ); // => struct class_attribute class_attr_mds static struct class *mds_class; static int my_dev_id; int __init init( void ) { int res = 0; mds_class = class_create( THIS_MODULE, "mds-class" ); if( IS_ERR( mds_class ) ) printk( KERN_ERR "bad class create\n" ); res = class_create_file( mds_class, &class_attr_mds ); if( res != 0 ) printk( KERN_ERR "bad class create file\n" ); if( request_irq( irq, mdsys_interrupt, IRQF_SHARED, "my_interrupt", &my_dev_id ) ) res = -1; return res; } void cleanup( void ) { synchronize_irq( irq ); free_irq( irq, &my_dev_id ); class_remove_file( mds_class, &class_attr_mds ); class_destroy( mds_class ); return; } module_init( init ); module_exit( cleanup ); MODULE_AUTHOR( "Oleg Tsiliuric <olej@front.ru>" ); MODULE_DESCRIPTION( "module in debug" ); MODULE_LICENSE( "GPL v2" );
Этот модуль получился прямой комбинацией нескольких примеров, которые мы написали раньше, так что все механизмы нам знакомы. Обработка ошибок при установке модуля практически отсутствует, чтобы не загромождать текст.
Для проверки того как это работает, загрузим модуль для контроля линии IRQ, например, сетевого адаптера (хотя это с таким же успехом могла бы быть и линия системного таймера):
$ cat /proc/interrupts | grep eth
16: 34985 0 IO-APIC-fasteoi i915, eth0
$ sudo insmod mdsys.ko irq=16
$ cat /sys/class/mds-class/mds
280
$ cat /sys/class/mds-class/mds
301
$ cat /sys/class/mds-class/mds
353
- здесь мы контролируем нарастающее значение счётчика сработавших прерываний. Изменим начальное значение этого счётчика, от которого происходит инкремент:
$ echo 10 > /sys/class/mds-class/mds
$ cat /sys/class/mds-class/mds
29
$ sudo rmmod mdsys
Подобным образом мы можем «вытащить» в наружу модуля сколь угодно много переменных для диагностики и управления.
Предыдущий раздел: | Оглавление | Следующий раздел: |
Тестирующий модуль | Комплементарный отладочный модуль |