null

Пересборка ядра в rpm-based дистрибутивах Linux

К сожалению в ядре Linux и в окружающем его железе не всегда все работает гладко и иногда требутется лезть туда напильником и что-нибудь допиливать. Очевидный способ состоит в скачивании свежего пакета исходников с kernel.org, и пересборке ядра, но он не красив в дистрибутивах типа RHEL, OEL, или SLES, в которых на ванильное ядро накладывается еще и куча патчей. Посмотрим, как правильно пересобирать ядро в таком случае.

Замечу, что способ использовался в Oracle Enterprise Linux 5, и отчасти в CentOS 6, поэтому не все особенности дистрибутивов могут быть учтены.

В первую очередь надо скачать и установить src-пакет ядра. В RHEL/OEL это делается с помощью утилиты yumdownloader из пакета yum-utils:
    # cd /tmp
   # yumdownloader --source kernel
   # rpm -i kernel*.rpm


Для SLES достаточно одной строчки:
    # zypper si kernel-default

После этого в /usr/src/ появятся файлы, содержащие исходные коды ядра и патчи вендора дистрибутива: /usr/src/redhat/SOURCES/ а в /usr/src/redhat/SPECS - spec-файл из которого собирается rpm-пакет ядра (в RHEL6 и OEL6 это будет директория /root/rpmbuild, в SLES - /usr/src/packages).

После этого создадим дерево исходников с уже наложенными на него патчами производителя. В этом нам поможет утилитка rpmbuild из пакета rpm-build:
    # cd /usr/src/redhat/SPECS
   # rpmbuild -bp kernel.spec

    Опция bp обозначает остановку сборки после стадии %prep

В /usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18-308.4.1.0.1.el5.i686 (имена последних двух директорий зависят от используемых версия ядра) появится дерево исходных кодов с патчами. Сделаем две его копии:
    # SRCPATH=/usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18-308.4.1.0.1.el5.i686
   # mkdir /root/linux-src
   # cd /root/linux-src
   # cp -r $SRCPATH linux-2.6.18.orig
   # cp -r $SRCPATH linux-2.6.18

    
Теперь можно вносить изменения в исходники ядра в директории linux-2.6.18/. Мне требовалось сделать сделать макросы параметрами ядра, из за особенности некоторых устройств под SunRay Software:
 

--- linux-2.6.18.4.orig/drivers/usb/core/hub.c  2012-05-14 15:20:27.000000000 +0400
+++ linux-2.6.18.4/drivers/usb/core/hub.c       2012-05-14 17:55:16.000000000 +0400
@@ -8,6 +8,8 @@
  *
  */
 
+#define _HUB_C
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -31,6 +33,13 @@
 #include "hcd.h"
 #include "hub.h"
 
+unsigned long usb_ctrl_get_timeout = 5000;
+module_param(usb_ctrl_get_timeout, ulong, 0777);
+
+unsigned long usb_ctrl_set_timeout = 5000;
+module_param(usb_ctrl_set_timeout, ulong, 0777);
+
+
 /* Protect struct usb_device->state and ->children members
  * Note: Both are also protected by ->dev.sem, except that ->state can
  * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
--- linux-2.6.18.4.orig/include/linux/usb.h     2012-05-14 15:20:42.000000000 +0400
+++ linux-2.6.18.4/include/linux/usb.h  2012-05-14 16:49:46.000000000 +0400
@@ -1044,8 +1044,13 @@
  * USB identifies 5 second timeouts, maybe more in a few cases, and a few
  * slow devices (like some MGE Ellipse UPSes) actually push that limit.
  */
-#define USB_CTRL_GET_TIMEOUT   5000
-#define USB_CTRL_SET_TIMEOUT   5000
+#ifndef _HUB_C
+extern unsigned long usb_ctrl_get_timeout;
+extern unsigned long usb_ctrl_set_timeout;
+#endif
+
+#define USB_CTRL_GET_TIMEOUT   usb_ctrl_get_timeout
+#define USB_CTRL_SET_TIMEOUT   usb_ctrl_set_timeout


 

После того, как необходимые изменения внесены в ядро, нужно сгенерировать патч с помощью diff -u:
    $ diff -u linux-2.6.32-71.el6.i686.orig/include/linux/usb.h \
     linux-2.6.32-71.el6.i686/include/linux/usb.h \
     > linux-2.6.18-usb-timeout.patch
$ diff -u linux-2.6.32-71.el6.i686.orig/drivers/usb/core/hub.c \
     linux-2.6.32-71.el6.i686/drivers/usb/core/hub.c \
     >> linux-2.6.18-usb-timeout.patch


Теперь нужно положить полученный файл вместе с остальными патчами и исходниками:
    # cp linux-2.6.18-usb-timeout.patch /usr/src/redhat/SOURCES/

Осталось отредактировать spec-файл, изменив в нем версию пакета (чтобы не перекрыть старое ядро) и добавить туда наш патч:
    %define distro_build 71 -> %define distro_build 71a
    
    перед строчкой:
    Patch999999: linux-kernel-test.patch   
    добавить:
    Patch200000: linux-2.6.18-usb-timeout.patch
    
В RHEL5 также потребуется добавить строчку
    %patch200000 -p1

Также будет полезно поменять в spec-файле версию ядра, иначе оно при инсталляции заменит текущее и мы рискуем получить неработоспособную систему.

Теперь можно запускать сборку:
    $ rpmbuild --without kdump \
             --without xen \
             --without pae \
             --without debug \
             --target=i686 \
             -bb kernel-my.spec

К списку статей

 

Интересуюсь по большей части системным анализом программного обеспечения: поиском багов и анализом неисправностей, а также системным программированием (и не оставляю надежд запилить свою операционку, хотя нехватка времени сказывается :) ). Программированием увлекаюсь с 12 лет, но так уж получилось, что стал я инженером.

Основная сфера моей деятельности связана с поддержкой Solaris и оборудования Sun/Oracle, хотя в последнее время к ним прибавились технологии виртуализации (линейка Citrix Xen) и всякое разное от IBM - от xSeries до Power. Учусь на кафедре Вычислительной Техники НИУ ИТМО.

See you...out there!

http://www.facebook.com/profile.php?id=100001947776045
https://twitter.com/AnnoyingBugs