К сожалению в ядре 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