Перейти к тексту

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

Профиль создается, когда вы в первый раз заходите в developerWorks. Выберите данные в своем профиле (имя, страна/регион, компания) которые будут общедоступными и будут отображаться, когда вы публикуете какую-либо информацию. Вы можете изменить данные вашего ИБМ аккаунта в любое время.

Вся введенная информация защищена.

  • Закрыть [x]

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

Вся введенная информация защищена.

  • Закрыть [x]

Нестандартные сценарии использования модулей ядра: Часть 46. Загрузка модуля ядра из кода другого модуля

Олег Цилюрик, преподаватель тренингового отделения, Global Logic
Фото автора
Олег Иванович Цилюрик, много лет был разработчиком программного обеспечения в крупных центрах разработки: ВНИИ РТ, НПО "Дельта", КБ ПМ. Последние годы работал над проектами в области промышленной автоматики, IP телефонии и коммуникаций. Автор нескольких книг. Преподаватель тренингового отделения международной софтверной компании Global Logic.

Описание:  Статья является частью миницикла, посвященного использованию модулей ядра для решения различных прикладных задач. В статье рассматриваются вопросы динамической загрузки и последующей выгрузки модулей ядра из кода других модулей ядра.

Дата:  07.02.2013
Уровень сложности:  средний
Активность:  1178 просмотров
Комментарии:  


Введение

В предыдущей части мы научились загружать и выгружать модули ядра из кода пользовательских приложений. Теперь мы рассмотрим вопрос, как сделать тоже самое из кода другого модуля ядра.


Загрузка модуля ядра из кода другого модуля

В предыдущей статье мы динамически загружали и выгружали модуль slave.ko из кода приложения, работающего в пространстве пользователя. Теперь нам предстоит сделать тоже самое, но уже из кода вызывающего модуля (master.ko). В листинге 1 приведён исходный код подобного модуля, который можно найти в архиве master.tgz в разделе "Материалы для скачивания".


Листинг 1. Модуль для загрузки другого модуля (файл master.c)

#include <linux/fs.hlinux_kernel_46 
#include <linux/vmalloc.h> 
#include "../common.c" 
#include "../find.c" 

static char* file = "./slave.ko"; 
module_param( file, charp, 0 ); 

static char this_mod_file[ 40 ],               // имя файла master-модуля 
            slave_name[ 80 ];                  // имя файла slave-модуля 
static int __init mod_init( void ) { 
   void *waddr; 
   long res = 0; 
   long len; 
   struct file *f; 
   void *buff; 
   size_t n; 
   asmlinkage long (*sys_init_module)          // системный вызов sys_init_module() 
              ( void __user *umod, unsigned long len, const char __user *uargs ); 

   set_mod_name( this_mod_file, __FILE__ ); 
   if( ( waddr = find_sym( "sys_init_module" ) ) == NULL ) { 
      printk( "! sys_init_module не найден\n" ); 
      res = -EINVAL; 
      goto end; 
   } 
   printk( "+ адрес sys_init_module = %p\n", waddr ); 
   sys_init_module = waddr; 
   strcpy( slave_name, file ); 
   f = filp_open( slave_name, O_RDONLY, 0 ); 
   if( IS_ERR( f ) ) { 
      printk( "+ ошибка открытия файла %s\n", slave_name ); 
      res = -ENOENT; 
      goto end; 
   } 
   len = vfs_llseek( f, 0L, 2 ); // 2 - means SEEK_END 
   if( len <= 0 ) { 
      printk( "+ ошибка lseek\n" ); 
      res = -EINVAL; 
      goto close; 
   } 
   printk( "+ длина файла модуля = %d байт\n", (int)len ); 
   if( NULL == ( buff = vmalloc( len ) ) ) { 
      res = -ENOMEM; 
      goto close; 
   }; 
   printk( "+ адрес буфера чтения = %p\n", buff ); 
   vfs_llseek( f, 0L, 0 );       // 0 - means SEEK_SET 
   n = kernel_read( f, 0, buff, len ); 
   printk( "+ считано из файла %s %d байт\n", slave_name, n ); 
   if( n != len ) { 
      printk( "+ ошибка чтения\n" ); 
      res = -EIO; 
      goto free; 
   } 
   {  mm_segment_t fs = get_fs(); 
      set_fs( get_ds() ); 
      res = sys_init_module( buff, len, "" ); 
      set_fs( fs ); 
      if( res < 0 ) goto insmod; 
   } 
   printk( "+ модуль %s загружен: file=%s\n", this_mod_file, file ); 
insmod: 
free: 
   vfree( buff ); 
close: 
   filp_close( f, NULL ); 
end: 
   return res; 
} 

static void __exit mod_exit( void ) { 
   asmlinkage long (*sys_delete_module)        // системный вызов sys_delete_module() 
              ( const char __user *name, unsigned int flags ); 
// flags: O_TRUNC, O_NONBLOCK 
   void *waddr; 
   char *slave_mod = strrchr( slave_name, '/' ) != NULL ? 
                     strrchr( slave_name, '/' ) + 1 : 
                     slave_name; 
   *strrchr( slave_mod, '.' ) = '\0'; 
   printk( "+ выгружается модуль %s\n", slave_mod ); 
   if( ( waddr = find_sym( "sys_delete_module" ) ) == NULL ) { 
      printk( "! sys_delete_module не найден\n" ); 
      return; 
   } 
   printk( "+ адрес sys_delete_module = %p\n", waddr ); 
   sys_delete_module = waddr; 
   {  long res = 0; 
      mm_segment_t fs = get_fs(); 
      set_fs( get_ds() ); 
      res = sys_delete_module( slave_mod, 0 ); 
      set_fs( fs ); 
      if( res < 0 ) 
         printk( "+ ошибка выгрузки модуля %s\n", slave_mod ); 
   } 
   printk( "+ модуль %s выгружен\n", this_mod_file ); 
} 

Функциональность модуля master.ko в точности совпадает с функциональностью рассматриваемого ранее пользовательского приложения, однако в данном примере присутствуют и моменты, специфические для модулей ядра. Так, для этого используются другие средства и инструменты, кроме того, все операции на уровне ядра должны выполняться с особой осторожностью. Необходимо учесть, что адреса системных обработчиков sys_init_module() и sys_delete_module(), которые формально не экспортируются ядром, нам неизвестны. Поэтому для выполнения этих вызовов нам необходимо:

  • найти адреса символов ядра sys_init_module и sys_delete_module с помощью функции find_sym(), как это уже делалось раньше;
  • присвоить эти адреса нашим собственным переменным: (*sys_init_module)(...) и (*sys_delete_module)(...) (имена этих переменных могут быть произвольными, но то, что они совпали с названиями системных вызовов, облегчает понимание кода);
  • выполнить косвенный вызов нужных функций по указателям *sys_init_module и *sys_delete_module;

Проверим работу созданного модуля:

$ sudo insmod master.ko 
$ dmesg | tail -n30 | grep + 
+ адрес sys_init_module = c0470f50 
+ длина файла модуля = 94692 байт 
+ адрес буфера чтения = f9d51000 
+ считано из файла ./slave.ko 94692 байт 
+ модуль slave.ko загружен: parm1=, parm2= 
+ модуль master.ko загружен: file=./slave.ko 

Предпоследняя строка системного журнала, выделенная курсивом, выведена из совсем другого модуля (slave.ko), в отличии от строк, обрамляющих её сверху и снизу.

$ lsmod | head -n4 
Module                  Size  Used by 
slave                   1001  0 
master                  1785  0 
fuse                   48375  2 

Модуль slave.ko был загружен после модуля master.ko, и между ними нет никаких зависимостей (по экспорту, связыванию и тому подобное), как это и должно быть.

Выгрузка модуля master.ko автоматически ведёт и к выгрузке модуля slave.ko:

$ sudo rmmod master
$ dmesg | tail -n30 | grep + 
+ выгружается модуль slave 
+ адрес sys_delete_module = c046f4e8 
+ модуль slave.ko выгружен 
+ модуль master.ko выгружен 
$ lsmod | head -n4 
Module                  Size  Used by 
fuse                   48375  2 
ip6table_filter         2227  0 
ip6_tables              9409  1 ip6table_filter 

Строка системного журнала, выделенная курсивом, опять же выведена из кода вызываемого модуля, в отличии от других строк, которые относятся к вызывающему модулю.


Заключение

В этой части цикла мы научились динамически загружать модули ядра не только из кода пользовательских приложений, но и из кода других модулей ядра. Данный подход потенциально позволяет создавать целые последовательности или иерархии загружаемых модулей, детальная конфигурация которых определяется непосредственно в момент загрузки. В следующей статье мы завершим рассмотрение вопросов динамической загрузки модулей, разработав законченное решение для расширения основной функциональности проекта с помощью автономных вспомогательных модулей-плагинов, подгружаемых по требованию.



Загрузка

ИмяРазмерМетод загрузки
master.tgz4KBHTTP

Информация о методах загрузки


Ресурсы

Об авторе

Фото автора

Олег Иванович Цилюрик, много лет был разработчиком программного обеспечения в крупных центрах разработки: ВНИИ РТ, НПО "Дельта", КБ ПМ. Последние годы работал над проектами в области промышленной автоматики, IP телефонии и коммуникаций. Автор нескольких книг. Преподаватель тренингового отделения международной софтверной компании Global Logic.

Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Спасибо. Эта запись была помечена для модератора.


Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Сообщение о нарушении не было отправлено. Попробуйте, пожалуйста, позже.


developerWorks: вход


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Выберите ваше отображаемое имя

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

(Должно содержать от 3 до 31 символа.)


Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Оценить эту статью

Комментарии

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=857578
ArticleTitle=Нестандартные сценарии использования модулей ядра: Часть 46. Загрузка модуля ядра из кода другого модуля
publish-date=02072013