Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

На главную -> MyLDP -> Электронные книги по ОС Linux
Цилюрик О.И. Модули ядра 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

Подобным образом мы можем «вытащить» в наружу модуля сколь угодно много переменных для диагностики и управления.


Предыдущий раздел: Оглавление Следующий раздел:
Тестирующий модуль   Комплементарный отладочный модуль