Text
                    МАТВЕЕВ М. Д.

Ядро

•

1nux
СБОРКА,Н АСТРОЙКА
УПРАВЛЕНИЕ

"Издательство Наука и Техника"

Санкт-Петербург


УДК 004.42 ББК 32.973 Матвеев М. Д . ЯДРО LINUX. СБОРКА, НАСТРОЙКА, УПРАВЛЕНИЕ НАУКА И ТЕХНИКА , 2023. - 352 СПБ.: ИЗДАТЕЛЬСТВО С., ИЛ . ISBN 978-5-907592-14-8 В этой книге собрана самая разнообразная и полезная информация о ядре Linux. Спектр материалов до статочно широк: от самых основ (компиляция ядра , загрузчик GRUB2, управление процессами (обработка до более сложных тем прерываний, таймеры и отслеживание хода времени, управление памятью ядра и т.д.). Отдельное внимание будет уделено различным аспек­ там файловой и псевдофайловой систем Linux, управлению хранилищем, механизмам кэ ширования чтени я и записи ядра. Также будет рассмотрено взаи модействие ядра с разными типами устройств и модулей , а для практики мы даже создадим свой несложный модуль. Книга будет полезна как начинающих линуксоидам, так и более опытным пользователям, которые хотят больше узнать о ядре Linux. В се права защище н ы . Никакая часть да нной кю1ги не может быть во спро ю ве,:хс н а в какой бы то ни было форме без п 11сьмеш1 о rо разрешения владельцев авторских прав . Издательство не несет ответственности за доступность матери ал ов . ссылки на которые вы м ожете найти а 3'tOi кинге . Н а м оме нт по.1готовюt кн и ги к и зданию все сс ылки на интер н ет-ресурсы был11 действующ им 11. 1SB N 978-5-907 592-14-8 9 J Ко нтакт ны е телефоны издательства: (8 12) 4 12 70 26 Официальный сайт : 211 www.nit.com. ru © Матвеев М . Д. © И здательство Н аука и Техника (о ригинал-макет)
Содержание ГЛАВА 1. ВВЕДЕНИЕ В ОПЕРАЦИОННУЮ СИСТЕМУ И ЯДРО LINUX ......................................................................... 11 1.1. НАЧАЛО. 1950-1990-ЫЕ ГГ.......................................................................................... 12 1.2. ИЗ 15 1.3. ЭТАП ДИСТРИБУТИВОВ MINIX ГЛАВА 2. В LINUX. ЭТАП ЯДРА .................................................................................. .............................................................................................. 16 ОСНОВНЫЕ СВЕДЕНИЯ: О ЯДРЕ ............................ 19 2.1. ЧТО ЕСТЬ ЯДРО 2.2. ОСОБЕННОСТИ ЯДРА 2.3. ВЕРСИЯ ЯДРА 2.4. ВЫБОР ЯДРА ПРИ ЗАГРУЗКЕ 2.5. СООБЩЕНИЯ ЯДРА ПРИ ЗАГРУЗКЕ ........................................................................ 28 2.6. ПЕРЕДАЧА ЯДРУ ПАРАМЕТРОВ ................................................................................ 30 ГЛАВА 3. ............................................................................................................... 20 LINUX ..................................................................................... 23 LINUX ..................................................................................................... 26 ..................................................................................... 27 КОМПИЛЯЦИЯ ЯДРА ................................................. ;.35 3.1. ПОЛУЧЕНИЕ ИСХОДНИКОВ ЯДРА 3.2. РАСПАКОВКА АРХИВА С ИСХОДНЫМ КОДОМ .................................................. 38 .......................................................................... 36 3.3. ИСПОЛЬЗОВАНИЕ ПАТ.ЧЕЙ ........................................................................................ 39 3.4. СОДЕРЖИМОЕ КАТАЛОГА С ИСХОДНЫМИ КОДАМИ 3.5. СБОРКА • ................................... 39 ЯДРА .................................................................................................................... 40 ·················································································· t l l l
И , 1р11 l .i1111, ...................... n.1nux 3.6. КОМПИЛЯЦИЯ МОДУЛЕЙ ........................................................................................... 43 3.7. УСТАНОВКА ЯДРА ................................................................ _.,...................................... 44 3.8. ПРАКТИЧЕСКИЙ ПРИМЕР: УСТАНОВКА ЯДРА 6.0 В ГЛАВА 4.1. 4. ЗАГРУЗЧИК ЗАГРУЗЧИКИ BUNTU 22.04 .......... 45 GRUB2 ....................................................... 49 LINUX ....................................................................................................... 50 4.2. КОНФИГ.УРАЦИОННЫЕ ФАЙЛЫ ............................................................................ 51 4.3. ВЫБОР МЕТКИ ·ПО УМОЛЧАНИЮ 4.4. ЗАГРУЗКА 4.5. ПАРОЛЬ ЗАГРУЗЧИКА 4.6. УСТАНОВКА ЗАГРУЗЧИКА 4.7. СИСТЕМА ИНИЦИАЛИЗАЦИИ .......................................................................... 57 WINDOWS ..................................................................................................... 58 GRUB2 .......................................... _ ....................................... 58 ................................................._ ...................................... 61 .................................................................................. 61 4.7, 1. Принцип работы ......................................................... ........................... 4.7,2. Конфигурационные файлы 62 systemd .................................................... 64 4.7.3. Цели ... ,.... ,........... .. ,.... ,.... ,........ ... .. ,......... ,.................. .......................... ,, . 67 4.8. УПРАВЛЕНИЕ СЕРВИСАМИ ПРИ ИСПОЛЬЗОВАНИИ ГЛАВА 5. SYSTEMD ................. 68 КАК ЯДРО УПРАВЛЯЕТ ПРОЦЕССАМИ .............. 71 5.1. ЧТО ТАКОЕ ПРОЦЕСС ................................................................................................... 5.2. СТРУКТУРЫ , СВЯЗАННЫЕ С ПРОЦЕССАМИ 72 ..................................................... 74 5.2.1. Список задач и структура процесса .................................................... 74 5.2.2. Состояния процесса .... ,., ..... ,..... ,....... ,,............. .... ,.... ,........ ,.................. 77 5.2.3, Дескриптор процесса ............... .............. ...... ., ........... .... .......... ...... ., ..... 79 5.3. КОНТЕКСТ ПРОЦЕССА ................................................................................................. 82 5.4. СОЗДАНИЕ НОВОГО ПРОЦЕССА И ЕГО ЗАВЕРШЕНИЕ ................................. 83 5.5. потоки 5.6. ПЛАНИРОВЩИК 5.7. УПРАВЛЕНИЕ ПРОЦЕССА МИ ИЗ КОНСОЛИ ....................................................... ............................................................................................................................... 87 .............................................................................................................. 91 92 • . ... .. ... . . . . .. . . . . .. .. . . . . . . . . . . . . . ·.· .................................... ... ...... .
Co. tl'p:m:aшн· n.1nux ................. . 5.7.1 . Командырs, nice и ki/1.......................................................................... 92 Получение информации о процессе .................................................... 92 5.7.2. Изменение приоритета процесса ......................................................... 97 Аварийное завершение процесса .... ........ .. ........ ...... .......... .... .......... .... 98 Команда top.......................................................................................... 100 5.7.3. Информация об использовании памяти и дискового пространства"102 5.7.4. Команда/иsеr ...................................................................................... 104 ГЛАВА 6. ОБРАБОТКА ПРЕРЫВАНИЙ ................................... 107 6.1. ЧТО ТАКОЕ ПРЕРЫВАНИЯ 6.2. ОБРАБОТЧИКИ ПРЕРЫВАНИЯ ................................................................................ ....................................................................................... 108 6.2 .1. Что такое обработчик прерывания? 6.2.2. Регистрация обработчика прерывания 109 ........................ .......... ...... .......... 109 ......... ........ .................. .......... 110 6.3. ПИШЕМ СОБСТВЕННЫЙ ОБРАБОТЧИК ПРЕРЫВАНИЯ .............................. 113 6.4. API ДРАЙВЕРОВ ВЫСОКОГО УРОВНЯ .................................................................. 116 6.5. КОНТЕКСТ ПРЕРЫВАНИЯ ......................................................................................... 117 6.6. ФУНКЦИЯ DO_IRQO ········································••,•···························································119 6.7. ИНТЕРФЕЙС /PROC/INTERRUPTS .......................................................................... 122 ГЛАВА 7. ТАЙМЕРЫ И ОТСЛЕЖИВАНИЕ ХОДА ВРЕМЕНИ .. 127 7.1. УЧЕТ ВРЕМЕНИ В ЯДРЕ ............................................................................................. 128 7.2. ТАЙМЕРЫ ЯДРА ............................................................................................................. 130 _ 7.3. API ТАЙМЕРА ................................................................................................................... 132 7.4. РЕАЛИЗАЦИЯ ТАЙМЕРОВ ЯДРА ............................................................................. 135 ГЛАВА 8.1. • 8. УПРАВЛЕНИЕ ПАМЯТЬЮ КАКАЯ БЫВАЕТ ПАМЯТЬ? ....................................... 139 ....................................................................................... 140 8.1.1. Физическая и виртуальная .................................. ........ ....................... 8.1.2. Файловая и анонимная 140 ................................................ ........ ............... 143 ·-······-··············-··-···--····-··--···-···-···---··--···--·---·······--···-· -
и 11111 l ,illll\ ....... . ............... n.lnux 8.1.3 . Вытесняемая и н е выте сня емая п ам ят ь ............................................. 144 8.1.4. Разные типы адресов .. .. ................. ................................ .. ............... .... 146 8.2. МЕТОДЫ УПРАВЛЕНИЯ ПОДСИСТЕМОЙ ПАМЯТИ ...................................... 148 8.2.1. Подкачка и невытесня ем ая п ам я ть ......................... .. ......................... 8.2.2. Систем ный вы з ов 8.2.3. ООМ 148 mlock() .................................................................. 148 killer ... ... ..... ............. ............. ......... ... ............. ........... ..... ..... ..... ... . 149 8.2.4. cgroups ................................................................................................. 150 8.2.5. NUМA ............................. ......................... ........ ... ..... ........... ..... ..... ....... 150 8.3. МЕХАНИЗМ РАСПРЕДЕЛЕНИЯ LRU ................................. :.................................... 151 8.4. ДОПОЛНИТЕЛЬНЫЕ СВЕДЕНИЯ ОБ УПРАВЛ Е НИИ ПАМЯТЬЮ В 8.4.1 . Снова о виртуал ьно й п амяти 8.4.2. Большие LINUX .. 153 .................. ............ ............................... 153 странИl\ы ................. .............. ... ............ .. ............ ........ .......... 155 8.4.3. Зоны ... .. :..... .......... ... ......... ....................... ...... ...................... ................. 155 8.4.4. Узлы ...... .... .... .......... .. .. .. ... .. .... ..... ... ................ .. ............. ........................ 156 8.4.5. Кэш страницы 8.4.6. Анонимная ... .. ..... ...... .... ........ .. ..... .. .... ... ... .. ... ............ ... .... .............. 156 па м ять .......... .................. ... ... ..:.................. ... .... .... ..... ...... . 157 8.4.7. Освобожд ени е ..... ..... ... ... .................... ..... ..... .................... ....... ............ 157 8.4.8. Уплотнение 8.5. (сжатие) .......... .. ...... .. .................. ...................... ............. . 158 БОЛЬШИЕ СТРАНИЦЫ. БОЛЕЕ ПОДРОБНО ...................................................... 8.5.1. Общая инфор м аци я 8.5.2. В з аимодействие ............................................................................ 159 п ол итики п амяти задач с выделением / освобождением б ол ьши х страни ц ....... ..... .. .. ..... ... ... ..... ... ...... .................. ... . 8.5.3. Атрибуты б ол ьших страниц для каждого узла 8.5.4. Испол ь з ование 8.6. 159 166 ................................ 166 больших стра н иц ...................................................... 167 ПРАКТИКУМ АДМИНИСТРАТОРА .......................................................................... 169 Полез ные команд ы оболоч ки .................................... ......................... 169 8.6.1. Файл /proc/meminfo ........... ........................................ ........................ . 169 Команда и ее улучш енны й ва риа нт top Ко м анда free Команда 8.6.2. lttop .................................... 170 ........................................................................................ 172 vmstat ..........................._. ........................................................ 173 Интерф ейс С МА. .... ... ................................................ ... ....................... 8.6.3. Добавл ение фа й ла п одкач к и 174 ................ ................ .. ............................ 174 • • - - ----------------·----·----------------------------·······················-·--·····
<· н tt•p ; 1,a1111t· n.1nux ................. . ГЛАВА 9. ФАЙЛОВАЯ СИСТЕМА И ЯДРО ............................ 177 ' 9.1. ВИРТУАЛЬНАЯ ФАЙ~ОВАЯ СИСТЕМА LINUX ................................................ 178 9.2. РЕГИСТРАЦИЯ И МОНТИРОВАНИЕ ФАЙЛОВОЙ СИСТЕМЫ ................... 180 ОБЪЕКТ СУПЕРБЛОКА ........................... ;................................................................... 9.3. 9 .3 .1. Структура struct super_ operations ..................................................... 184 9.3 .2. Структура structxattr_hand/ers ......................................................... 187 9.4. ОБЪЕКТ ИН ОДА 9.5. ОБЪЕКТ АДРЕСНОГО ПРОСТРАНСТВА ............................................................................................................. 188 9.5. 1. Общая ОБЪЕКТ 9.6. 183 информация .............................................................. 192 ............ ........................................................ ........ 192 9.5.2. Обработка ошибок во время обратной записи .. .. .... ._ ....... .. ........ ....... 9 .5 .3. Структура 194 sutruct address_ space_ operations .................................... 195 FILE ................................................................................................................... 202 9.7. КЭШ ЗАПИСЕЙ КАТАЛОГА (DCACHE) ................................................................. 207 9.7 .1. Структура dentry_ operations .............................................................. 207 9.7.2. АР ! кэша записей каталогов ............................................................... 211 ГЛАВА 10. ПСЕВДОФАЙЛОВЫЕ СИСТЕМЫ ....................... 213 10.1. НАЗНАЧЕНИЕ ................................................................................................................ 214 10.2. ПСЕВДОФАЙЛОВАЯ СИСТЕМА SYSFS ............................................................... 215 10.3. ПСЕВДОФАЙЛОВАЯ СИСТЕМА PROC ................................................................ 216 ГЛАВА 11.1. ПОЛЬЗОВАТЕЛИ И ГРУППЫ 11. ВВЕДЕНИЕ В УЧЕТНЫЕ ЗАПИСИ ................................ 221 LINUX ......................................................., .. 222 11.2. ПОЛУЧЕНИЕ ПОЛНОМОЧИЙ ROOT .................................................................... 225 11.3. УПРАВЛЕНИЕ УЧЕТНЫМИ ЗАПИСЯМИ ПОЛЬЗОВАТЕЛЕЙ ..................... 231 11.3 .1. Создани е уч етной записи пользователя ....... ....................... ........ .. .. 11.3.2. Файлы /etc/passwd • . - - 11 .3.3. - - - - - - --- - - - - - - - - - - и Изменение и удаление учетных записей - - - - - - - - - . . . - . -. - - - - - - 23 1 /etc/shadow ........................ .. ............. .... ........... 233 - - - - - .- - - - - ........................................ 236 -. -- . - . - - - - - - - -. -- . -- - - -
Я . tро (,iпux ............ . .......... n..1nux 11 .3 .4. 11.4. Группы пользователей .............................. ........ ................ ................ 240 МОДУЛИ РАМ ................................................................................................................. 11.4.1. Ограничиваем доступ 11.4.2. Ограничиваем 11.4.3. к системе по IР•адресу 241 ............................ ... 244 время входа в систему ............................................. 246 Ограничение системных ресурсов с помощью РАМ .................. ... 247 ГЛАВА 12. БЛОЧНЫЙ ВВОД/ВЫВОД ....................................... 251 12.1. БЛОЧНЫЕ У(;ТРОЙСТВА ......................................................................................... 252 12.2. СТРУКТУРА БЛОЧНОГО УСТРОЙСТВА ............................................................ 253 12.3. БУФ ЕРЫ ........................................................................................................................... 254 12.4. ПЛАНИРОВЩИКИ ВВОДА/ВЫВОДА .................................................................... 257 12.4.1 . Алгоритм deadline ............................................................................ 258 12.4.2. Алгоритм CFQ .. ..... ........... ,.... .................... ..... ................ ................... 259 12.4.3 . Алгоритм NOOP ....................... ...................... ..... ... ........ ... ................ 259 12.4.4. Настройка планировщиков ...... ..................... ...... ....... ........ ..... ......... 260 Настройка пла нировщика CFQ .................. .............. ..................... ... 261 Настройка планировщика deadline ................................................. 263 12.5. НАСТРОЙКА ОБЩИХ ПАРАМЕТРОВ БЛОЧНОГО ВВОДА/ВЫВОДА ..... 264 ГЛАВА 13. МЕХАНИЗМЫ КЭШИРОВАНИЯ ЧТЕНИЯ И ЗАПИСИ ЯДРА LINUX ....................................................... 267 13.1.ДИСКОВЫЙ КЭШ И ОТЛОЖЕННАЯ ЗАПИСЬ ................................................. 268 13.2. МЕТОДЫ КЭШИРОВАНИЯ 13.3. КЭШИРОВАНИЕ НА ПРАКТИКЕ ............................................................................ ...................................................................................... 269 273 ГЛАВА 14. УСТРОЙСТВА И МОДУЛИ ..................................... 279 14.1. ТИПЫ УСtРОЙСТВ ..................................................................................................... 280 14.2. МОДУЛИ ЯДРА ...................................•............................................................................ ... 14.2.1 . Написание простого модуля 281 .................................................... ........ 281 • . . ----. ---. ---- ----------------------------- ------- ----------. -- --.. ---. ----------
C11. trp,ю11111t· rt..inux ................. . 14.2.2. Сборка модуля ................. ... .............. .............................. ................... В пределах дерева исходных кодов ядра Вне дерева исходников ядра 14.2.3. ........................................... .. ....... .... ... . 286 Установка модулей ...... ..... .. ... ........... .... .... ......................................... 14.2.4. Загрузка 284 ............. .......................... . 284 модулей ............. ......... ............. .... .......................... .............. 286 286 14.3. РАЗРАБОТКА СЛОЖНЫХ МОДУЛЕЙ ................................................................... 287 14.3 .1. Компиля ция модулей из нескольких файлов исходного кода ....... 14.3.2. Зависимости 14.3.3. ГЛАВА 15. между модулям и Загрузка модулей с зависимостями ........... ...................................... УПРАВЛЕНИЕ ХРАНИЛИЩЕМ ПОДКЛЮЧЕНИЕ НОВОГО ЖЕСТКОГО ДИСКА И ЕГО РАЗМЕТКА 15.2. МЕНЕДЖЕР ЛОГИЧЕСКИХ ТОМОВ 15.3. в 288 ........................... 291 15.1. 15 .2. l . Введение 287 ................................ ........ ................ 288 ....... 292 ................................................................... 300 LVM ......................... ... ...................... .. .................. .......... 300 15 .2.2. Уровни абстракции 15.2.3. Немного пра ктики .... ...... ... .......... .......... .. .. ... ..... ... ............. ..... .... ....... 302 РАСШИРЕНИЕ LVM-ПPOCTPAHCTBA ................................................................. 305 LVM ..................... .. ..................... .. .................... 301 ПРИЛОЖЕНИЕ 1. ФАЙЛЫ КОНФИГУРАЦИИ LINUX ........ 309 Пl.1. КОНФИГУРАЦИОННЫЕ ФАЙЛЫ ........................................................................ 310 Пl.2. ПОДКАТАЛОГИ С КОНФИГУРАЦИОННЫМИ ФАЙЛАМИ ........................ 319 ПРИЛОЖЕНИЕ 2. КОМАНДНЫЙ ИНТЕРПРЕТАТОР BASH.. 329 П2.1. НАСТРОЙКА BASH ..................................................................................................... 330 П2.2. ЗАЧЕМ НУЖНЫ СЦЕНАРИИ BASH ..................................................................... 334 П2.3. СЦЕНАРИЙ "ПРИВЕТ, МИР!" ................................................................................ 335 П2.4. ПЕРЕМЕННЫЕ В СЦЕНАРИЯХ ............................................................................. 336 П2.5. ПЕРЕДАЕМ ПАРАМЕТРЫ СЦЕНАРИЮ ............................................................. 338 • .. . -... - - .. . - - - -. -- -. -- - .. - - - - - ... - ....... - - - .. - - - . - .. - - - - - .- - - - . -- - . - - - .-.- ... - - --
И , 1рн l , i1111, ....................... n.,nux П2.6. ОБРАБОТКА МАССИВОВ П2.7. ЦИКЛЫ FOR И ........................................................................................ 339 WHILE ............................................................................................... 339 П2.8. УСЛОВНЫЕ ОПЕРАТОРЫ ............................. :......................................................... 340 П2.9. ФУНКЦИИ В BASH................................... ,.................................................................. 342 П2.10. ПРАКТИЧЕСКИЕ ПРИМЕРЫ СЦЕНАРИЕВ .................................................... 343 Проверка прав пользователя .. ,.. ........ ........ ............................... .. ... .. ............. Проверка свободного дискового пространства с уведомлением по 343 e•mail .... 343 ПРИЛОЖЕНИЕ 3. СЕТЕВАЯ ФАЙЛОВАЯ СИСТЕМА NFS .. 345 ПЗ.1. ВКРАТЦЕ О NFS И УСТАНОВКЕ НЕОБХОДИМЫХ ПАКЕТОВ ................. 346 П3.2. ФАЙЛ /ETC/EXPORTS ........................ j....................................................................... 347 ПЗ.3. ИСПОЛЬЗОВАНИЕ NFS-KЛИEHTA ...................................................................... СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ ИНФОРМАЦИИ . . ... .. .. .. -....... ....... ......... ---- ... - . --- 349 ...................... 350 • -- ................ ---- -- -- -- ---- ... -..
Глава 1. Введение в операционную систему и ядро Linux
Я , 1р11 1,iщl\ ...................... t'l.inux 1.1. Начало. 1950 Говоря об истории поскольку Linux Linux 1990-ые гг. нельзя не начать с операционной системы зарождалась не на ровном месте. Когда говорят о первое , что приходит на ум об этой операционной системе распространяется по лицензии OpenSource, - UNIX, Linux, то это то, что она то есть исходные коды самой операционной системы абсолютно свободно доступны и любой желающий может ними воспользоваться , в том числе и для создания собственного программного продукта. Подробно о самой лицензии говорить не будем - в Интернете полно информации на эту тему. Не нужно думать, что Linux - это первая ОреnSоurсе-операционная систе­ ма. Нет, в 1950-ые годы практически все программное обеспечение в США разрабатывалось студентами и распространялось абсолютно бесплатно. Ни­ каких ограничений на распространение ПО не было - вы могли взять ис­ ходные коды любого продукта и использовать их как вам пожелается. Тогда еще не существовало лицензии OpenSource, но никто даже не задумывался о лицензировании программных продуктов. Первой операционной системой, которая распространялась свободно была малоизвестная система А-2, кото­ рая была написала для UNIVAC Remington Rand. На рисунке 1.1 этот компьютер, занимающий всю комнату средних размеров. изображен • 81111-....... -------... -... --....... --............... -... --........ --.. --... -... -------.
t\.1nux ........... . 1 1 1а11а 1. Рис. В11t·щ·11щ• 11 нщ•р:11111111111~ ю t·11t· 1 t·м~ 11 i1 . 1p11 l .i1111, 1.1. UNIVAC Remington Rand В 50-ые годы прошлого века началось зарождаться ОреnSоurсе-движение, тогда оно называлось группой Share - результатом работы этой группы была одноименная операционная система, появившаяся в конце 1950-ых. Также в конце 50-ых годов компания ADR начала разрабатывать програм­ му для автозаполнения блок-схем. В силу определенного стечения обсто­ ятельств этой компании свой программный продукт пришлось переделать для платформы IВМ401 , но коммерческого успеха у данной платформы не было , ведь все ждали бесплатное решение от ADR. Сама же компания ADR не могла допустить выход бесплатного продукта, иначе бы она стала банкро­ том. Поэтому ее разработчик, желая получить хоть что-то, продал патент на программу в 1968-ом году. Эту дату считают датой коммерциализации ПО и датой, когда ПО из полезного бонуса к «железу» превратилось в отдельный продукт. Параллельно , в том же 1968-ом году специалисты из операционную систему (англ. patch - Multics. Bell Labs возрождают Они планировали сделать небольшой патч заплатка), который перерос в отдельную операционную си­ стему для мини-компьютера на­ зываться мы знаем PDP-7. Новая операционная система стала Unics. Именно так - мы не опечатались . Изначально то, что как Unix, называлось Unics. ' ················································································-
}l,1po 1,i1111, ....... . .............. n.1nux Первые версии Unics были написаны на ассемблере, но позже код был пере­ писан на языке высокого уровня С и проект был переименован в . сделало Unix. Это новую операционную систему более портативной и простой в ис­ пользовании. Изюминкой (кроме портативности) стала иерархическая фай­ ловая сисцма с одним корневым каталогом. Поскольку холдинг АТ &Т, в состав которого входила Bell Labs, подписал соглашение с правительством США, запрещающее компании продавать про­ граммное обеспечение, исходный код Unix был доступен бесплатно . В пер­ вую очередь его получили научные организации. В 70-ые годы Калифорнийский университет в Беркли получил лицензию от АТ &Т. Группа энтузиастов разработала свой вариант тив, который получил название UNIX - свой дистрибу­ BSD - Berkeley Software Distribution. В начале 80-ых АТ &Т отказались от концепции бесплатного распростране­ ния ПО, Поэтому параллельно существовали две версии BSD UNIX - и коммерческая от АТ &Т. Открытая операционная система стала популярной , особенно в начале 80-ых, когда Unix бесплатная BSD сразу от АТ &Т переста­ ла бесплатно распространяться . По вполне понятным причинам компании АТ &Т это не понравилось , и она подал_а в суд на университет. В результате университету Беркли пришлось переписать существенную часть кода заимствованный из Теперь об Unix OpenSource. - весь код . История зарождения открытого ПО началась в конце 70-х годов прошлого века, когда программист Мэттью Столлман запросил исходный код драйвера принтера у коллег из Массачусетского технологиче­ ского института, но получил отказ . Данный факт обидел Столлмана, которо­ го не устраивали ограничения, наложенные на обмен исходниками . Поэтому он решил создать операционную систему с открытым кодом - любой жела­ ющий мог бы вносить в нее изменения . В сентябре 1983 года он объявил о создании проекта GNU (GNU's Not Unix), В основе проекта лежал манифест, который стал фундаментом для лицензии GPL (General PuЬ!ic License), что и стало началом движения OpenSource. Несколько лет спустя Эндрю Таненбаум разработал Uniх-подобную опера­ ционную систему Minix, которая планировалась как учебное пособие для Minix тогда стоила 69 долларов - довольно недо­ студентов. Лицензия на рого, поэтому в начале 90-ых эта система завоевала популярность среди раз- работчиков , • • 8 1 8 ---------------------------------------------------------------------------------·
1т111а I n..inux ........... . 1.2. Из Minix в Ввt•. 1t•111н· 11 11ш· ра1111111111~ ю t· 1н· 1 t·,1~ 11 11 lfНI Linux. l .i1111, Этап ядра Собственно, сама операционная система Minix не была полноценной опе­ рационной системой . Она создавалась для демонстрации основных прин­ ципов настоящих (полноценных) операционных систем. Ее полный исход­ ный код, который занимал всего тысяч строк, был опубликован в книге 12 А.Таненбаума «О перационные системы». Данную книгу купил Линус Тор­ вальдс (Linus Torvalds). В 1991 году Линус установил Minix, но разочаровался в ней . на свой компьютер операционную систему Он принял решение усовершенствовать ее - ведь исходный код «Миникса» был доступен со всеми комментариями. Сна­ чала он просто переписал программу эмуляции терминала, а затем фактиче­ ски взялся за создание собственной операционной системы. Linux. Конеч­ Linux, которую мы знаем, но она уже тогда была лучше своего прародителя - в ней работали командный интерпретатор bash и компилятор gcc. Сообщение о создании новой опе­ рационной системы было помещено в группу новостей comp.os.minix, там 25 августа 1991 года появилась на свет операционная система но, это была еще не та операционная система же предлагалось всем желающим протестировать ее . :Кроме информации о выходе новой ОС в новостном письме было несколько тезисов относительно новой операционной системы. Если вкратце , то : • Исходный код полностью переписан (то есть идея , но весь код для Minix использовался как был написан заново). Linux v.001 • Linux не будет такой громоздкой как • Linux распространяется бесплатно. Кстати, изначально Линус GNU. называл ядро своей операционной системы Freaks, но администратору FТР-сервера , на который заливались исходники новой операционной системь1 , такое название не понравилось и он переиме­ новал его в Linux. После публикации новости о сивное развитие Linux, к энтузиасты со всего мира , • Linux в группе comp.os.minix началось интен­ ее разработке в помощь Торвальдсу подключились - ничто так не сокращает расстояния , как Ин­ тернет. С момента появления версии 0.01, которой практически нельзя было • ················································· ··· ···· ·························· 8 1 1
И IJIO l .i,111, ...................... n..1nux пользоваться , до создания версии 1.0, пригодной для обычных пользовате­ лей, а не программистов , прошло почти три года (она появилась в марте 1994 года) . Первая версия обладала поддержкой сети (поддерживался протокол TCP/IP), а также графическим интерфейсом Х Window. Кстати, система Х Window появилась в Linux еще в 1992 году одновременно с поддержкой TCP/IP. На секунду, Windows 3.11 , которая появилась в ноябре 1993 году, поддержкой сети не обладала. Поддержка сети появилась лишь в версии Windows 3 .11 for Workgroups. выше коммерческого детища Первые версии Linux Так что с самого начала Linux была на голову Microsoft. распространялись на обыкновенных дискетах. Всего было две дискеты: первая содержала ядро , а вторая - корневую файловую систему и необходимые программы. Именно поэтому данный этап в раз­ витии Linux мы назвали этапом ядра . По сути , кроме ядра и некоторых не очень сложных утилит в самом начале ничего не было. Установить подобную версию Linux на компьютер мог только специалист. Чуть позже появились первые дистрибутивы, которые включали то же ядро и корневую файловую систему, а также программу для установки всего этого на компьютере. Программа установки поставлялась , как правило, на отдель­ ной дискете . Изначально Linux распространялся без лицензии GPL. Другими словами, разработчики могли использовать ядро , модифицировать его, но не могли перепродавать результаты своих трудов. 1.3. Этап дистрибутивов Что такое дистрибутив Linux? По сути - это ядро и дополнительные программы. Любой желающий (даже сейчас) может создать собственный дистрибутив Linux, определив набор и параметры программ, входящих в его состав. Собственно, создать дистрибутив не очень сложно и это под силу од­ ному, технически грамотному IТ-специалисту (понятно, когда есть команда, то работа пойдет быстрее). Первые дистрибутивы появились в 1992 году. Тогда отдельные энтузиасты или группы э нтузиастов выпускали разные дистрибутивы (каждый, есте­ .. ственно , под своим именем) . Фактически они отличались друг от друга лишь , названием и программой установки . В дальнейшем различия между дистри­ бутивами стали более существ енными . ........ ... .. .... ........ .. .. ...... .. . . . . . ... . . ... .. .... ... . ......... ... . .. .. . ..
n..1nux ........... . 1 1, 111. 1 1 B11t',' tt· 1111t• 11 с1ш· ра1111с11111~ ю 01i· н· м~ 11 " -' IJIO 1, i1111x Самый первый дистрибутив, появивший ся в начале МСС Interim Linux (Manchester Computing Centre, 0.12 терный центр). Он был создан на базе версии 1992 года, назывался Манчестерский компью­ в феврале 1992 года. Ав­ тор дистрибутива ставил перед собой цель усовершенствовать процедуру установки ядра и добавить несколько полезных функций . МСС стал примером для всех остальных. Вскоре стали появляться другие дистрибутивы. Многие из них прожили совсем недолго и мало кому извест­ ны, например, дистрибутив TAMU, разработанный в Техасском университе­ те. Настоящий прорыв произвел дистрибутив Softlanding_Linux_ System), SLS (https://ru.wikipedia.org/wiki/ 1992 года, поскольку графическую систему Х Window выпущенный в октябре именно он содержал поддержку TCP/IP и (автор этой статьи помнит, сколько труда тр'ебовалось, чтобы настроить ее). Впоследствии данный дистрибутив бурно развивался и постепенно транс ­ формировался в один из самых популярных дистрибутивов того времени - Slackware. Да, SLS много не прожил. Всего два года, но зато он послужил основой для дистрибутива Slackware, который существует и по сей день. Первая версия Slackware увидела свет 17 июля 1993 года. Slackware - отличный пример классического дистрибутива. Да, в нем нет всяких модных примочек , как в UЬuntu, он не обновляется каждые два года, но это тот самый хотите, true linux. Впрочем , Gentoo Linux - Linux. Если тоже пример дистрибутива для настоящих фанатов , обладающих свободным временем . В 1993 году также появился и второй популярнейший дистрибутив - Debian. Автор дистрибутива - Иан Мердок. Дистрибутив создан при поддержке FSF (Free Software Foundation) Столлмана. Изначально задумывался как альтер­ натива SLS, но получился даже более удачным. На сегодняшний день явля­ ется наиболее удачным и стабильным дистрибутивом в мире. На его базе был создан ряд других дистрибутивов, в том числе мега-популярный ·дис­ трибутив UЬuntu . Дистрибутивостроение развивалось не только в США. В Германии в 1992 SUSE (Software- und System Entwicklung). Они первые начали выпускать Linux для бизнес-клиентов. По сути, сначала они выпускали адаптированную для немецкого рынка версию Slackware. году была основана компания Со временем дистрибутивы разрослись до таких размеров , что распростра­ нять их на дискетах стало нель з я. Дистрибутив на 50 дискетах - - вполне реально. А что делать, если, скажем, дискета №41 окажется бракованной? • .-.......... --- ...... . ... -- ... ......... -....... --- ..... --.........................
Я ; tро ...................... n.iпux [,inux Как раз к тому времени компакт-диски и их приводы немного подешевели. Компания Red Hat была одной из первых, выпустивших свою разра,ботку на CD. Начиная с середины 90-ых, все дистрибутивы Linux постепенно переш­ ли на CD, а затем - на DVD . Первая версия Red Hat появилась в 1995 году. Современные дистрибути вы распространяются, как правило, в виде ISО­ образа DVD-диска. Далее этот образ записывается либо на DVD, либо на флешку и производится установка на физический компьютер. С виртуаль­ ным еще проще - ISО-образ «подсовывается» виртуальной машине и произ­ водится установка системы на виртуальный диск . Мы сейчас не будем рассматривать этапы развития даже самых популярных дистрибутивов, поскольку ядро унифицировано, а надстройка над ядром (то есть ПО, входящее в состав дистрибутива) не является предметом этой книги. • . . . --- ----- ----- -- ·- ---- ---. --- ----•----•-- ---- ---· -----.- ---- -- ----·- ---------- -- --·
• Глава 2. Основные сведения о ядре
Я 1 1рс1 2.1. J, i1111x ....................... rt.inux Что есть ядро Говоря о ядре по умолчанию понимаешь, что это основной компонент систе­ мы. Вроде бы и так понятно, но информатика - наука точная, поэтому давай­ те разбираться, какой именно компонент операционной системы называется ядром и за что он отвечает. Ведь из-за роста возможностей само понятие операционная система стало очень размытым. Многие считают, что все, что они видят на экране (кроме прикладных программ) и есть операционная система . С одной стороны, это так и есть. Ведь операционная система - это та часть компьютерной системы , которая отвечает за основные функции использования и администрирования. Сюда же входит ядро, драйверы устройств, системный загрузчик, команд­ ная/графическая оболочка, файловая система и базовые системные утилиты. В общем, только минимально необходимые для работы компьютера компо­ ненты. Не является частью операционной системы прикладное ПО - тексто­ вый редактор , браузер, медиа-проигрыватель и т.д. А вот понятие система охватывает все ПО на компьютере - и операционную систему, и прикладные программы. Понятно , что ядро является частью операционной системы . Можно сказать, что интерфейс пользователя (будь то командная строка или графическая обо­ лочка) является внешней частью ОС , а ядро - внутренней. • E!lt-· ....... -.... -...... --....... --···-· ....... -.--............................... ·-.
n..iпux .... ........... .. . Ядро - 1J lalШ 2. Основные CBC)(CIIIOI о ядре это программное обеспечение, предоставляющее базовые функции для всех остальных частей операционной систем,ы. Именно ядро управляет аппаратным обеспечением («железом») и распре­ деляет системные ресурсы . В англоязычной литературе можно встретить термины супервизор (supervisor), основная часть (core), «внутренности» (intemals) - это и есть ядро. К компонентам ядра относятся: • Обработчики прерываний, которые обслуживают запросы на прерыва­ ния, поступающие от различных устройств; • Планировщик, распределяющий процессорное время между многими процессами ; • Система управления памятью, которая управляет адресным простран­ ством процессов; • Системные службы, такие как сетевая подсистема и подсистема межпро­ цессного взаимодействия. Обычно ядро находится в привилегированном положении по отношению к пользовательским программам, то есть у ядра есть полный доступ к «же­ лезу» и ко всем областям защищенной памяти . Систем,ные перем,енные (system state) и обл асть памяти, в которой находится ядро, вместе называ­ (kemel-space). ются пространством ядра Прикладным программам доступна лишь малая часть ресурсов, они не мо­ гут выполнять некоторые системные функции, напрямую работать с аппара­ турой, системной памятью (то есть не могут выходить за рамки адресного пространства, которое выделено прикладной программе ядром). Прикладные программы взаимодействуют с ядром с помощью системных вызовов. Посмотрите на рис. 2.1. Допустим, нашей программе нужно открыть файл. Для этого она использует системный вызов open(). Програм­ (user mode ), далее она обращается к конкретном примере - выполняет код ма работае:r в пользовательском режиме режиму ядра, которое что-то делает. В реализации функции open() и возвращает какой-то результат (например, код ошибки или дескриптор открытого файла). • • • ······························ ····· -··············································-
и , ,, ... l ,illll\ •············ · ········· fl1пux user application ) user mode system call interface kernel mode open ( ) lmplementation of open ( ) system call return Рис. 2.1. Программа и системный вызов орепО Когда прикладная программа выполняет системный вызов, говорят, что ядро выполняет работу от имени прикладной программы. Более того, говорят, что прикладная программа выполняет системный вызов в пространстве ядра, а ядро выполняется в контексте процесса. В функции ядра входит также управление системным аппаратными компо­ нентами, Все платформы , на которых работает операционная система • (и Linux не только) используют механиз.м прерываний (inteпupt). Когда аппаратно ­ му устройству необходим о как-то в за имодейст вовать с системой, оно поставляет на шину специальный сигнал, который, в буквальном смысле слова, прерывает работу процессора : Далее процессор запускает специаль­ ную программу в ядре (обработчик прерывания , inteпupt handler), причем все это происходит в реальном масштабе времени . Каждому типу прерыва­ ния соответствует определенный номер - именно так можно узнать, какой именно обработчик нужно запустить. Например , при вводе символа с клави­ атуры контроллер клавиатуры генерирует прерывание , чтобы дать знать си­ стеме, что в буфере клавиатуры есть новые данные , которые еще не обрабо­ .. таны операционной системой . Ядро определяет номер прерывания , которое пришло в систему, и з апускает соответ ствующий обработчик прерывания . • -·:. ---... -.. ---- ---. -- --. --- ·- ---- -------- -- -- . -- -. -... -- --. ---- ---... ---- -. .. -. -
1 11; 111.1 rl1nux ................. . :' Оt·1ю1111ыt· t"llt',' H'IIIШ 11 )Цl)t' Последний обрабатывает данные, поступившие с клавиатуры, и дает знать контроллеру клавиатуры о том, что ядро готово для приема новых данных. Во многих операционных системах, в том числе и в Linux, обработчики пре­ рываний выполняются не в контексте процессов, а в специальном контек­ сте прерывания (interrupt context), который не . Данный контекст существует специально, связан ни с одним процессом, чтобы дать возможность обработ­ чику быстро отреагировать на прерывание и завершить работу. В случае простоя система запускает в ядре в контексте процесса специаль­ ный холостой процесс (idle process), Поэтому можно сказать, что процессор всегда находится в одном из трех режимов: l, Выполнение прикладной программы в непривилегированном режиме; 2. Выполнение операций в контексте процесса в привилегированном режи­ ме от имени определенного процесса; 3. Обработка прерываний в контексте прерывания, не связанном с каким-то процессом. 2.2. Особенности ядра Linux Все сказанное ранее можно отнести к ядру любой операционной системы, не только Linux. Понятно, что у каждого ядра есть свои особенности. Мы сейчас не будем рассуждать о ядре той же об особенностях ядра Linux Windows, а лучше поговорим на фоне ядер других Uniх-подобных систем. В большинстве своем все ядра Unix являются монолитными бинарными файлами. Они существуют в виде больших исполняем111х образов, которые выполняются в одном адресном пространстве. Для работы таких ядер тре­ буется система с контроллером управления страничной организацией па­ мяти (page memory management unit, MMU). Такое <<железо» позволяет защитить память в системе и предоставить каждому процессу уникальное виртуальное адресное пространство. Для работы Linux также нужен Существуют отдельные реализации, позволяющие работать без позволяет запускать рых нет блока ММU. • Linux MMU. MMU, что на миниатюрных "3Строенных системах, у кото­ - .--• -------------·- ----------------------------------------.. --. --. --------. ------. •
Я 1 1ро l,in11x _·_ ...... __ . __ .......... n.inux Ранее было отмечено, что ядро Unix/Linux является монолитным. А какие еще ядра бывают? Ядра операционных систем можно разделить на две боль­ шие группы по особенностям их построения: м01-юлитные и микроядра. Монолитное ядро является самым простым и до середины 1980-ых годов все ядра были монолитными. Монолитное ядро реализовано в виде одного большого процесса, который выполняется в одном адресном пространстве. Такие ядра обычно хранятся на диске в виде одного большого статического бинарного файла . Все службы ядра находятся и выполняются в одном боль­ шом адресном пространстве ядра. Взаимодействия в ядре осуществляются очень просто, потому что все, что выполняется в режиме ядра, выполняется в одном адресном пространстве. Можно отметить простоту и высокую про­ изводительность монолитных ядер. При ·реализации микроядра обычно разработчики отказываются от одного большого процесса. Все функции ядра разделяются на несколько процессов, которые называются серверами. В привилегированном режиме работают только определенные серверы, а все остальные работают в пользователь­ ском. Все серверы изолированы и независимы друг от друга и каждый за­ пускается в собственном адресном пространстве. Прямой вызов функций, как в случае с монолитным ядром ; невозможен. Все взаимодействия с ядром осуществляются посредством механизма межпроцессного взаимодействия (IPC, Interprocess Communication). Даже сами серверы взаимодействуют друг с другом через IPC. Разделение серверов позволяет предотвратить воз­ можность выхода из строя одного сервера при выходе из строя другого. Бо­ лее того, модульный принцип построения системы позволяет по мере необ­ ходимости одному серверу выгрузить из памяти другой сервер. Наличие дополнительного механизма (речь идет об IPC) требует дополни­ тельных ресурсов по сравнению с обычным вызовом функций, что приво­ дит к падению производительности системы по сравнению с монолитны­ ми ядрами. Типичцый пример микроядра - 'ядро операционной системы Windows NТ. Подобное ядро используется во всех современных версиях Windows, включая 1О и 11. В последних версиях Windows все серверы вы­ полняются только в пространстве ядра, что является отклонением от перво­ начальной идеи микроядра, но позволяет повысить производительность, так как не нужно постоянно переключаться между пользовательским и привиле­ гированным режимами. Ядро Linux .. монолитное, т.е. оно выполняется в одном адресном простран­ стве, в режиме ядра . Однако ядро Linux позаимствовало некоторые хорошие - • . -- -------.. -... --.. ---... -.. --... -... ---. --... -........ --...... -.... --... .. . --..
1тша 2. n.inux ................. . OCIIOBIIЫC СВСДСIIИЯ II sщрс решения из микроядерной модели: в нем используется модульный принцип построения, возможность приоритетного планирования самого себя программн.ым режимом, ( его называют ядром с приоритетн.ым мульти­ или kernel preemption ), поддерживается многопо­ точный режим, а также возможность динамической загрузки в ядро внешних бинарных файлов (модулей ядра). Далее в этой книге мы поговорим об этом - вам не нужно собирать ядро, содержащее в себе весь необходимый функ­ ционал. Некоторый функционал может быть включен по мере необходимо­ сти в ядро посредством загрузки модуля . Ядро Linux не использует никаких функций микроядерной модели, которые бы могли привести к снижению производительности: все выполняется в ре­ жиме ядра с непосредственным вызовом функций вместо передачи сообще­ ний. Следовательно, операционная система Linux - модульная, многопо­ точная, с приоритетным планированием самого ядра. Рассмотрим следующие особенности ядра Linux - то, чем оно отличается от других Uniх-подобных систем: • Ядро Linux поддерживает динамическую загрузку модулей ядра . Хотя ядро и является монолитным, его функционал можно расширить без пе­ рекомпиляции ядра путем динамической загрузки исполняемого кода из модуля. • Ядро SMP (симметричную многопроцессорную об­ Современные Unix также поддерживают SMP, но традицион­ Unix, существовавшие в момент, когда появилась Linux, такой Linux работку). ные ядра поддерживает поддержки не имели. • В ядре Linux поддерживается приоритетное планирование. В отличие от традиционных версий ОС Unix, ядро Linux в состоянии прервать выпол­ нение текущего задания, даже если оно работает в режиме ядра. Если го­ ворить о Solaris и Unix, то поддержка приоритетного планирования есть только в IRIX. В большинстве ядер других вариантов такая возможность отсутствует. • В Linux принята объектно-ориентированная модель устройств, в которой поддерживаются классы устройств, события, возникающие ripи горячем подключении устройств, и файловая система в пространстве пользовате­ ля • sysfs (userspace device filesystem) . ·--------------------------------------------------------------------------------- ...
и 11111 l ,illll\ • В ядре • В ядре ....................... n.1nux Linux используется интересный подход для поддержки многопо­ точности (threads): потоки ни чем не отличаются от обычных процессов. Linux отсутствуют некоторые функции ОС Unix, которые разра­ ботчики посчитали плохо спроектированными, как, например, поддержка интерфейса STREAMS, или поддержка стандартов, которые невозможно аккуратно реализовать 2.3. Вереи~ ядра Linux Прежде , чем мы приступ к следующей главе, нужно поговорить о версиях и вариантах ядра. Начнем с вариантов. Существуут два варианта ядра - стабильный (staЫe) и разрабатываемый (development). Разрабатываемый вариант переходит в стабильный по окончанию тести­ рования. То есть новые стабильные версии ядра обычно выпускаются для исправления ошибок и предоставления новых драйверов устройств. В раз­ рабатываемых версиях ядра допустима некорректная работа некоторых ком­ понентов - это в порядке вещей, поскольку ядро еще не объявлено стабиль­ ным. Поэтому для production-cиcтeм , таких как серверы,, рабочие станции обычных пользователей подходят только стабильные варианты ядра. Для энтузиастов, желающих попробовать новые функции ядра, которые еще не стали достоянием общественности, и помочь сообществу разработчиков протестировать эти самые новые возможности, как раз и предназначен раз­ 'рабатываемый вариант. Понять, какой вариант ядра используется конкретно в вашей системе, очень просто: по номеру версии. Версию ядра всегда представляют три или четыре числа. Если числа четыре ку четвертое число - - - перед нами (major) - номер младшей версии dеv-вариант, если четный dеv-вариант - (minor), а первое версии. Также можно понять, какое ядро перед нами по номеру младшей версии. Если он нечетный • 4.1.2 - выпуск, посколь­ это как раз номер стабильной версии. Третье число номер выпуска, второе число основной номер 100% стабильный - значит перед нами стабильный. Рассмотрим примеры: (minor = 1) • 8 8 ···············-·-·----·---·---··--··---·---··---·---··---·---··--·----·-·-··-·-··
1J laвa n.1nux . •................ . • 4.2 - 2 . Ot·11c111111.1t· c:иt•J tt'IIIHI CI Щ{llt' стабильный вариант (два последних числа опуще ны), (<стабиль­ ность» определяется по четному значению • 4.2.10.1 - minor. стабильный вариант, номер выпуска бильной версии (revision) = 1О , номер ста­ - 1. Процесс разработки ядра включает несколько фаз. Вначале разработчики ядра работают над новыми функциями, что напоминает хаос. Через опре­ деленное время ядро оказывается сформировавшимся, и, в конце концов, объявляется о замораживании функций. Начиная с этого момента никакие новые запросы на 1щлючение новых функций в ядро не принимаются . Счи­ тается, что ядро достигло стабильного уровня и его исходный код заморажи­ вается. 2.4. Выбор ядра при загрузке У вас (даже если установлен всего один дистрибутив) может быть установ­ лено несколько ядер. Напри~ер , вы можете установить дистрибутив, в нем будет одна версия ядра, а затем установить более новую версию ядра вруч­ ную. При загрузке вы сможете выбрать нужную вам версию ядра. На рис. 2.2 показано меню загрузчика выбрать одну из версий ядра • Рис. 2.2. Astra Linux, где пользователю - generic или hardened. предлагается Выбор ядра при загрузке системы ... -... -. --- -. -. -... --- -- -- ---- ------ . ---- --. -· -- - . ---- . -. -...... ---- --- -- ---. -... . . .
Ядро Linux ....................... t'l.inux Вторая версия повышает общую защищенность системы от взлома. Так, h ardened-ядpo умеет блокировать массу потенциально опасных операций, а компилятор hardened-gcc позволяет защитить компилируемые им програм­ мы от взлома типовыми методами вроде переполнение буфера. Грубо гово­ ря , если у вас стоит «дырявая» версия программы Х, и ее пытается взломать хакер , то в обычной системе у него это получится, а в hardened - не полу­ чится, да еще и в лог запись пойдет. Номер версии ядра выводится при входе в систему (если вы входите в консо­ ли) или его можно узнать командой ипате -а (рис. что в UЬuntu 20.04 используется версия ядра Рис. 2.3. 2.3). На рис. 2.3 5.4.С - даже не 5.7.0. показано, Команда ипате -а 2.5. Сообщения ядра при загрузке При загрузке ядро выводит сообщения, просмотреть которые можно коман­ дой: dmesg I les s . ........ •
1 11, 111.1 _) n_,nux ................. . Ot· 1ю11111.1t• t·щ•, 1t•111111 1111щн· Обычно сообщения ядра понятны сами по себе без особых комм е нтариев . Например , в самом начале выводится версия ядра и переданные ядру пара­ метры : 0.000000) Linux version 5 . 4 . 0- 39 - generic (buildd@lcy01 - amd64-016) (gcc version 9 . 3.0 (Ubuntu 9 . 3 . 0- 10ubuntu2)) #43 - Ubuntu SMP Fri Jun 19 10 : 28 : 31 UTC 2020 (Ubuntu 5.4.0 - 39 . 43 - generic 5.4.41) 0.000000) Command line : BOOT_IМAGE=/boot/vmlinuz - 5.4 . 0 - 39-generic root=UUID=05fd3e4e-1605 - 478c - 8db9 - bбdf62a01ad3 ro quiet splash Карта физической памяти : 0 . 000000) 0 . 000000) 0 . 000000] 0 . 000000] 0 . 000000] 0 . 000000) 0 . 000000 ] 0 . 000000) 0 . 000000) 0 . 000000) 0.000000) О . 000000] BIOS- e820 : BIOS- e820: BIOS- e820 : BIOS- e820 : BIOS- e820: BIOS- e820: BIOS- e820: BIOS- e820: BIOS- e820 : BIOS- e820 : BIOS- e820: BIOS- e820 : [mem [mem [mem [mem [mem [mem [mem [mem [mem [mem [mem [mem 0x0000000000000000- 0x000000000009efff] usaЫe 0x000000000009f000- 0x000000000009ffff] reserved 0x00000000000ca000- 0x00000000000cbfff] reserved 0x00000000000dc000- 0x00000000000fffff] reserved 0x0000000000100000- 0x000000001fedffff] usaЫe 0x00000000lfee0000- 0x00000000lfefefff] ACPI data 0x00000000lfeff000- 0x00000000lfefffff] ACPI NVS 0x00000000lff00000- 0x00000000lfffffff] usaЫe 0x00000000e0000000- 0x00000000efffffff] reserved 0x00000000fec00000- 0x00000000fec0ffff] reserved 0x00000000fee00000- 0x00000000fee00fff] reserved 0x00000000fffe0000,- 0x00000000ffffffff] reserved Сообщит, что найдена SМР-таблица (значит, наша машина является много­ процессорной или хотя бы содержит процессор с несколькими ядрами) : 0 . 000000) found SMP at МР - tаЫе at [mem 0x000fбbf0 - 0x000fбbff] mapped [ffff8800000fбbf0 ] Выведет информацию о процессоре: 0 . 694470) smpboot : CPU0 : Intel(R) Core(TM) i5 - 7200U CPU@ 2 . 50GHz (family: Охб , model: Ох8е , stepping: Ох9 ) 0.715491) smp : Brought up 1 node , ·2 CPUs Частоту процессора и рейтинг в «попугаях»: • ··---. ·-- ... -·· ......... . -- ·---· ·---. -- -··- -- ...... -... ·-·. ·- -···· ............... --
И , 1р11 l .i1111x •······················ rtiпux 0.00000 1 ) t sc : Detected 2711 . 997 MHz processor 0 . 71 54 91) smpboot : Total of 2 processors activated (10847 . 98 BogoMIPS ) это псевдорейтинг, который показывает, сколько миллионов BogoMIPS - пустых операций процессор может выполнить за секунду. Судить о произво­ дительности по этому рейтингу можно только косвенно. Исследуйте вывод ядра самостоятельно. Уверен, в нем вы найдете много ин­ тересного, в том числе и о своей системе. 2.6. Передача ядру параметров Поскольку ядро - это щ~ограмма, то ней можно передать параметры, влия­ ющие на поведение ядра. Первым делом разберемся, как передать ядру па­ раметры . Сначала в меню загрузчика нужно выбрать загрузочную запись, которую вы хотите отредактировать (рис. 2.2). Далее нужно нажать е для ре­ дактирования конфигурации загрузчика. Среди строк конфигурации найдите строку, которая начинается со слова загрузки ядра после него - Linux. Сразу после «linux» «linux». GRUB2 Это и есть строка указывается путь к ядру, а все, что это и есть параметры ядра . Отредактируйте имеющиеся пара­ метры или добавьте новые параметры в конец строки. В главе 4 будет показано, как сохранить конфигурацию GRUВ2 (после пе­ резагрузки внесенные_ вами изменения будут потеряны, поэтому их нужно внести в конфигурационные файлы Ctrl+x для Самые основные часто используемые параметры ядра описаны в таблице 2.1. GRUB2), а пока нажмите загрузки с отредактированной вами конфигурацией. Таблица 2.1. Часто используемые параметры ядра Параметр Linux Описание Параметры корневой файловой системы Указывает устройство, содержащее корневую фай- rооt=устройство ловую систему. Вы можете указать, как короткое имя устройства (/dev/sdal), так и UUID устройства ., . ....... .. ... .. ....... -... -----. -. ---.. --... --. ---... -... --.. -- ... --... -.. -- -.. --...
1J la!Ш 2. n..inux ----------- -- ----- Ос11ов11ыс CRC) {CIНIЯ () Я ) (рС Тип корневой файловой системы. Обычно в нем нет rootfstype=тип необходимости, поскольку ядро само определяет ти п ФС Ядро будет ждать появления устройства с корневой файловой системой. Вы можете держать ядро на жест- ком диске, а корневую файловую систему на rootwait USB- д иске. С точки зрения производительности может и не очень хорошо , но зато неплохо с точки зрения безопасности, когда весь жесткий д иск с данными можно быстро извлечь и удалить rootdelay=N Подождать N секунд перед монтированием файловой системы Монтирует корневую ФС в режиме «тол ько чтение». После проверки утилитой/сsk корневая ФС будет ro перемонтирована в режим гw Монтирует корневую ФС в режим «чтение/зап ись». Но тогда вам нужно отредакти ровать сценарии ини- rw циализации системы и удалить из них вызов утилиты fsck, поскольку проверять ФС в режиме ,-w этой ути - литой нельзя Параметры , связаю-1ые с аппаратными средствами llOSCSI Отключает поддержку SCSI nousb Отключает поддержку USB nopcmcia Откл ючает поддержку РСМСIА-карт noap1c дите при загрузке сообщение об ошибке , связанной с Отключает поддержку APIC. Полез ен, если вы уви- APIC • .-... -· ....... -.... -... - ...... , ........... -- .............. -.. -. -. -........ -. -... -. . .
Ящт l ,i1111x notlmraid mem=xxxxM ................•....... n.1nux Отключает прогр аммные RАID-массивы, созданные на уровне BIOS Задает точный размер оперативной памяти , например , mem=4096M Задает VGА-режим . Можно попросить ядро позволить vgа=режим вам выбрать оди н из режимов , передайте ядру такой пар аметр - vga=ask Параметры управления питанием noapm acpi=off Отключает расширенно е управление питанием АРМ Отключает . . pc1=noacp1 ACPI (Advanced Configuration and Power Interface) Отключить APCI для PCI Общесистем.ные параметр ы Позволяет указать систему инициализации. Во многих системах, если указать в качестве <программа> /Ьin/ bash init=программа вы получите тот же однопользовательский ре- жим, но при этом система не будет запрашивать у вас пароль root, поэтому такая лазейка часто используется для обхода системы безопасности и несанкционированного доступа rеЬооt=тип single .. quiet Указывает тиri перезагрузки : warm (теплая) или cold (холодная) Однопользовательский режим, которы й может использоваться для восстановления системы в случае сбоя Отключает большинство сообщений ядра при загрузке системы ' . . -- ..... . -............. -............................... . ....... . ... .. .... . ... . ... .
1 1:111:1 ainux ........ ......... . Задает задержку в 2 0t'IIШllll,lt' t'llt', lt'IIIHI II И . ll)t' N секунд перед выводом следующе­ го сообщения ядра. Система будет загружаться очень boot_delay=N медленно , лучше дождаться загрузки , выполнить ко­ манду dmesg и в спокойной обстановке прочитать все сообщения • .. --... -. ----......... ...... ..... -........................................... -.... -
Глава 3. Компиляция ядра
И 1 tр11 l ,i1111x ...................... n.1nux В этой главе мы в общих чертах рассмотрим получение исходных кодов, компиляцию и установку ядра в произвольной Linuх-системе-без привязки к какому-то дистрибутиву. Однако в каждом дистрибутиве есть свои особен­ ности, поэтому мы также рассмотрим весь этот процесс в UЬuntu получение и установку ядра 3.1. 22.04 - 6.0. Получение исходников ядра Исходный код ядра Linux можно скачать с сайта kernel.org. На этом сайте доступна как последняя версия ядра, так и архивы с предыдущими версия­ ми. Вы можете скачать как полный исходный код, так и инкрементный патч, позволяющий повысить версию ядра без закачки всех исходников. Такие патчи удобны, если вы, например, скачали, откомпилировали и установили ядро, скажем, версии 5.4, а затем хотите перейти на версию 5.6. В этом слу­ чае вам не нужно опять скачивать исходники, которые довольно объемны, а достаточно скачать только патч (набор изменений), который превратит вашу версию 5.4 в более новую 5.6. • . . ........................... . .......................................................
t\.inux ____ ~ ____ . _. ______ . I . 1 ана ] . Ко,11111 . 1я11ш1 я , 1ра Тhе Unux Kemel Archives .1,оо..( Protoeot Ctint.tctus FAQ R~ Srtenews Loc.aoon НТТF T,;n:::м-r.•,.J.~or9fp,;c: Grт https:t :9!t_i<efr~!)(9,' f<S't'NC ~yтx::;;rsync.kerrie'-Or(J/p.11)/ Latest Retease 6.1.6(!) m,ift!м: 61-n:4 2023,-01-15 s~bl.f' 6.t6 6.0.'19{EOLJ 2023-01•14 (\.,t~ЪЗЦJ 202Н)1-12 {tilJl'DiЩ {pgpJ st.lЬl.e: ~ longtt!rm: 5,15,88 longtemt 5..IOJ63 {t;,rЬ.JЩ [pc;;pl (P4ctl] [mc p«"..h] [>kw d:ff] (ЬrowиJ (p,щt,J !кх p,щhJ {Ьrc;,,-1\.\!'J (<!'·>iП19"\09] [view c,lfJ {p.ttd1] {,nc.p.,t::h} [.--,d.;ff) {hra,,,"!:~} [ c . ~ J 2023-а!·\.4 [tart!JЩ lpqpJ (p.tt~h] {tr.( ~t,h] [ww cHfJ f~-s4!] [ < ~ 202)-01..14 l~lU {pqp] [patd,j {ll"IC.~td1] ['l!f№tciiff'J {brc-f,;~~J ( c ~ J 2022-12-i9 t~a~ilJ INPI {pact!] {н·к p,.1Ш"IJ {-.,"!t'\", c:,ff] [~""::-eJ [с~~ Ю2.2-12-14 l~J] {pgpJ lp,tdt! firoc. puthJ !'МW o:tf] (Ьw,vstJ { c r ~ J Lon9term: 5.4.228 longten-n: 4..19.269 longtмn: 4.\4.302 2022-12•14 [t;,ri).1:l] [P9PJ !pгtd1) ['1'!( p.,t::hj {--.-, d:ffJ [orov.-::t] [c:~lo,;j tDngtem,: 4..9.337 [EOLJ 2023-ОЧ)7 [..1rnai.lJ (P9PJ {~rthj (irx ~,h] !VteW a.ffJ tью,,мJ {(r~togJ Ur..A~xt: nut-20130t17 2023-0\-17 Other moun:es Рис. 3.1. Сайт Sacial www.kerneLorg, Как видите, можно скачать где можно скачать самые разные версии ядра tarball (архив с расширение tar.gz), а также патч (patch). Однако загрузка исходников с сайта kemel.org - это для новичков . Если у вас уже есть опыт разработки на одном из современных языков программирова­ ния, скорее всего, вы уже знакомы с Git - Git. это система версий, позволяющая отслеживать вносимые отдельны­ ми разработчиками изменения в проект программного обеспечения. Примечательно, что Git также был разработан Линусом Торвальдсом имен­ но для обслуживания исходных кодов ядра Linux, когда другие подобные системы перестали соответствовать его требованиям . Если опыт работы с Git у вас есть, сам будет гораздо проще использовать git для получения исходников ядра: $ gi t clone • git://git . kernel.org/puЬ/scm/linux/kernel/git/torvalds/linux.git ·--------------------------------------------------------------------------------- -
}11р11 l.i1111, ...................... n.1nux После загрузки исходного кода нужно обновить дерево до состояния послед­ него обновления, которое сделал Линус. Для этого введите следующее: $ git pull Данные команды позволяют загрузить последнюю версию ядра Linux с последними правками . Если нужна определенная версия ядра, тогда, можно ее указать при получении репозитария: $ git clone git : linux - 6 . 2 . gi t 3.2. // git.kernel.org / puЬ/scm / linux / kernel / g i t / t o rvalds / Распаковка архива с исходным кодом Получив исходные коды, нужно их откомпилировать. Архив кода ядра распространяется в сжатых форматах .tar исходного GNU zip (gzip) и bzip2 . Фо.рмат bzip2 лучше, поскольку он обеспечивает больший коэффициент сжатия по сравнению с форматом имя linux-x.y.z.tar.bz2, где x.y.z - gzip. Архив ядра в формате bzip2 имеет номер соответствующей версии исходного кода ядра. После загрузки файла его нужно распаковать с помощью простой команды. Если .tаr-архив сжат с помощью утилиты bzip2, введите такую команду : $ tar xvjf linux - x . y .z.t ar . bz2 Если сжатие выполнено с помощью gzip, то команда должна иметь следую­ щий вид : $ tar xvzf linux -x. y . z . tar . gz Обе эти команды позволяют разархивировать и развернуть дерево исходных кодов ядра в каталог linux-x.y.z. При использовании Git для получения ис­ ' ходного кода ядра и управления им вам не нужно загружать архив в формате . . ..---------------. --------------. --.. ---. ---. ---.. ---. ----••• -.. ------------. ----.
1 1,111,1 , n..1nux ..... .. ........... . .tar. Просто введите команду git clone, К1ш1111 . 1ш1ш1 ii 1ра как было описано ранее, и она сама загрузит и распакует самую последнюю версию дерева исходного кода ядра . 3.3. Использование п атч ей Если вы скачали не полный исходный код, а только заплатку (патч), тогда применить ее можно так : patch - p l < .. / patch - x . y.z $ Разумеется , нужно перейти в каталог, содержащий дерево исходных кодов (в каталог, в который вы распаковали архив с исходниками) и сами исходники должны существовать (должны быть ранее загруженными). 3.4. Содержимое каталога с исходным и код ами После распаковки исходного кода в папку li"nux-x.y.z вы обнаружите множе­ ство подкаталогов . Рассмотрим их содержимое: исходный код, специфичный для аппаратной платформы . • arch Ыосk • - слой блочных операций ввода/вывода. • crypto - криптографический • Documentation • drivers - различная документация. • драйверы устройств. • firmware • fs - API. микропрограммы устройств , необходимые для использования подсистема виртуальной файловой системы и отдельные файловые системы . • include - заголовочные файль1 ядра. • init - код для загрузки и инициализации ядра. • ipc - код межпроцессного взаимодействия. , _ --. --... --.. -------. ----. ---.. ---. ---.. -... --- . --... --.. --.. -.... ---. ----. --- . --
Я . 1ро [,inux • kernel - • lib - ______________________ n..inux основные подсистемы ядра , такие как планировщик . вспомогательные подпрограммы. • nm - подсистема управления памятью и поддержка виртуальной памяти. • net - сетевая подсистема . • samples • scripts - сценарии компиляции и построения ядра . • security • sound • tools • usr • virt - примеры и демонстрационный код. модуль безопасности Linux. звуковая подсистема. вспомогательные утилиты для разработки Linux. код инициализации пространства польз ователя. инфраструктура виртуализации. Кроме подкаталогов в каталоге с исходниками будут несколько файлов. Самый главный файл 3.5. - Makefile, содержащий инструкции по сборке ядра. Сборка ядра Сборка ядра достаточно проста и в некоторых случаях даже проще, чем сборка некоторых других программных продуктов. Но при сборке ядра нуж­ но первым делом его сконфигурировать. Ведь ради этого часто и устраивают перекомпиляцию ядра , поскольку при установке системы ядро то уже отком­ пилировано и прекрасно работает. Часто целью перекомпиляции является добавление нового функционала в ядро - поддержку необходимых драйверов • и функций . Поскольку в ядре существует бесчисленное количество функций и вариантов поддерживаемого аппаратного обеспечения, возможностей по конфигурации , мягко говоря, много . Процесс конфигурации выполняется с помощью указания ряда параметров конфигурации в виде CONFIG_ФУНК­ ЦИЯ. Например, поддержка симметричной многопроцессорной обработки (Symmetric multiprocessing, SMP) устанавливается с помощью параметра CONFIG_SMP. Если этот параметр установлен, то поддержка функций SMP включена. Если не установлен , то функции поддержки SMP отключены. Па­ раметры конфигурации используются как для определения того , какие фай- • . . . . . ...............................................................................
I ~ iaвa n..inux __________________ _ 3. Ко\11111 . 1я1щя я . 1ра лы должны быть скомпилированы во время сборки ядра, так и для управле­ ния процессом компиляции через директивы препроцессора. Параметры конфигурации, которые управляют процессом сборки ядра, бывают двух типов: логические (boolean) и с тремя состояниями (tristate). Логические параметры могут принимать значение ло, параметры конфигурации ядра наподобие yes или по. Как прави­ CONFIG_PREEMPT являются логическими. Параметры конфигурации с тремя состояниями могут nри­ нимать значение yes, по или module. Значение module означает, что данный параметр конфигурации установлен, но соответствующий ему код должен быть скомпилир<,шан в виде модуля (т.е. как отдельный объект, который за­ гружается динамически). В случае параметров конфигурации с тремя со­ стояниями значение yes явно указывает на то, что соответствующий код должен быть скомпилирован в основной файл образа ядра, а не в виде моду­ ля. Драйверы устройств обычно определяются параметрами конфигурации с тремя состояниями . Параметры конфигурации можно задавать также в виде строк символов или чисел. Эти параметры не управляют процессом сборки ядра, а позволяют указать значения , которые встраиваются в исходный код с помощью дирек­ тив препроцессора . Например, с помощью параметра конфигурации можно указать размер статически размещаемого массива. Ядра многих дистрибутивов компилируются как часть дистрибутива и даже поставляются в виде RРМ/DЕВ-пакетов. В таких дистрибутивах может быть несколько уже скомпилированных ядер, например, одно с поддержкой другое - SMP, без поддержки. Вы можете установить нужный пакет с помощью обычного менеджера пакетов, ядро установится, а потом выберите его в меню загрузчика при загрузке системы или настроите автозапуск нужного ва!-1 ядра. Но иногда бывает, ч:го ядро нужно скомпилировать, например, для реализа­ ции поддержки определенного оборудования, самостоятельно. Или же вы хотите попробовать новую версию ядра - как правило, энтузиасты этим часто заморачиваются. В любом случае у каждого свои причины перекомпи­ лировать ядро, если вам это нужно, то вы должны знать зачем. Конфигурирование ядра осуществляется или посредством редактирования файла .config или же с помощью специальных утилит. Редактировать вруч­ ную можно, если вам нужно включить/выключить r,Iapy опций, и вы точно знаете, как они называются. Во всех остальных случаях нужно использо­ вать утилиты конфигурации. Для запуска утилит конфигурации используйте одну из трех команд : '-------------------------------------------------------------------------------- -818
Я 1р11 1 . iща $ - - - ___________________ t'linux ma ke config $ make menuco nfig $ make gconfig Первая утилита работает в текстовом режиме. Она будет работать всегда, в отличие от той же Linux gconfig, которая не будет работать , если вы установили без поддержки графического интерфейса (на серверах он лишний). Вторая наиболее удобная - она и удобнее, и работает в консоли. В этих трех утl):литах все параметры конфигурации делятся на категории вроде Processor Туре and Features (Типы и свойства процессора). При этом пользователь имеет возможность перемещаться по категориям , просматри­ вать параметры конфигурации ядра и, разумеется , изменять их значения. Иногда бывает так, что вы внесли изменения в конфигурацию , перекомпи­ лировали и установили ядро , а система после этого не запускается или же что-то работает некорректно . Нужно загрузиться с использованием преды­ дущего ядра и ввести команду: $ make defconfig Данная команда позволяет создать файл конфигурации, содержащий стан­ дартные значения параметров для текущей аппаратной платформы . После этого нужно снова перекомпилировать и установить ядро , либо же попы­ таться снова - внести изменения в конфигурацию и при этом быть более внимательным . Параметры конфигурации сохраняются в файле .config, который находится в корне дерева каталогов исходного кода ядра. Большинство разработчиков считают, что гораздо проще непосредственно отредактировать этот файл конфигурации. В самом деле, с помощью любого текстового редактора достаточно легко выполнить поиск нужного параметра в этом файле и из­ менить его значение. После внесения изменений в файл конфигурации или при использовании существующего файла конфигурации для нового дерева каталогов исходного кода ядра, его необходимо ратифицировать и обновить конфигурацию с помощью команды $ make oldconfig • - - ----------------------------------------------···-----···--------------·---------·
1 1,111,1 ' n..lnux .................. . k°ll\11111 . IIIIIIHI 11 tpa Эту команду вам также нужно запустить перед сборкой ядра . Параметр кон­ фигурации CONFIG_IKCONFIG_PROC позволяет сохранить все текущие параметры конфигурации ядра в виде сжатого файла его в каталог config.gz и поместить /proc. Это позволит вам легко создать клон текущей конфигура­ ции при сборке нового ядра. Если этот параметр конфигурации установлен в вашем текущем ядре , то просто скопируйте файл config.gz из каталога /proc и воспользуйтесь им для создания нового ядра, как показано ниже. $ zcat /p roe / config.gz > . config $ make oldconfig После того , как вы сконфигурируете ядро , его можно откомпилировать. Для этого введите команду : $ make Выполнение команды make занимает весьма прилично времени. Сколько именно, зависит от производительности вашего компьютера. Бывает так, что компиляции ядра нужно ждать несколько часов. Но ничего не поделаешь, придумайте , чем заняться это время . 3.6. Компиляция м одулей После компиляции ядра нужно также откомпилировать модули. Когда вы настраиваете функции ядра с помощью программы конфигуратора, вы мо­ жете ту или иную функцию выключить, включить или же оставить включен­ ной в виде модуля - вариант М . Включать нужно те функции, которые вам нужны всегда, а вот если функция постоянно не нужна, например, tюдцерж­ ка какого-то устройства, которое потенциально вам может пригодиться, вы можете оставить ее включенной в виде модуля. После компиляции ядра вам нужно откомпилировать модули, то есть все функции, которые вы пометили как М. Для компиляции модулей нужно ввести команду : $ make modules • .. . -- -----...... -..... -. ---. ------------ .. ---------.. -. -. ---.. ----. -... --. ----·. -. -
Я . tро l,iщ1x ______________________ n..inux Время выпо.i:~нения этой команды зависит от количества функций, которые вы отметили как М. Тоже придется подождать некоторое время. После компиляции модулей их нужно установить: $ sudo make modules install 3. 7. Установка ядра После з авершения процесса сборки ядра его нужно проинсталлировать в системе . Процесс инсталляции существенно зависит от используемой аппа­ ратной платформы и типа системного загрузчика. Вы можете найти различные руководства в Интернете, описывающие слож­ ный процесс установки ядра. В современном мире нужно ввести только две следующие команды: $ sudo make install $ sudo update-grub Перед вводом второй команды загляните в каталог /Ьооt. В нем должно быть два файла : initrd . img-6 . 0.0 - rc7 vm linuz-6.0.0-rc7 Номер версии может у вас отличаться . Первый файл мяти инициализации (lnit RАМ Disk), второй - - это образ диска па­ собственно, сам файл ядра. Вывод второй команды будет примерно таким: Sourcing file '/ etc/default/grub ' Sourcing file '/etc/ default /g rub.d/init-select.cfg' Generating grub configuration file ... Found linux image: / boot / vmlinuz - 6.0.0 - rc7 Found initrd image: /boot/ initrd.img-6.0.0-rc7 . . . ---- --- --------------------------- ---- -------------------- -------------------- _,
1 с1а11а , n.1nux .................. . Found Found Found Found Found Fo u nd К11,11111 . 1шщsr ~цра l inux i mage : /boot/vmlinuz - 5 . 15 . 0 - 46 - gener i c initrd image : /boot/initrd .img - 5 . 15 . 0 - 46 - g e ne r ic linux image : /boot/vmlinuz-5 . 13 . 0 - 30 - gener i c initrd ima ge : /boot/initrd . img - 5 . 13 . 0 - 30 - gene r ic memtes t 86+ image : /boot/memtest86+ . elf memtes t 86+ image : /boot/memtest86+ . b i n Команда sudo нужна для устано вки ядра (первая команда) и обновл ения конфигурации загруз чика (вторая команда) . После этого можно перезагру­ зить систему командой reboot и Примечание. пробовать новое ядро . Компилировать ядро вы можете как обычный пользователь, а вот для установки ядра нужны полномочия 3.8. Практический пример: установка ядра Пbuntu 6.0 root. в 22.04 Представим , что у нас есть последняя версия дистрибутива UЬuntu. Понят­ но, что разработчики дистрибутивов не всегда поспевают за разработчиками ядра и бывает, что в последней версии дистрибутива версия ядра далеко не самая последняя . Попробуем проапгрейдить ядро до версии 6.0 (установка других версий, по крайней мере линейки 6 . х, будет выполняться аналогич­ но) на примере дистрибутива UЬuntu. Первым делом посмотрим , какая версия ядра используется в данный момент: uname -а Вывод будет таким: Linux ubuntu2204 5 . 15 . 0- 33- generic #34 - Ubuntu SMP Wed UTC 2022 х86 - 64 х86 - 64 х86 - 64 GNU/Linux Установим все необходимые пакеты для сборки ядра - Мау 18 13 : 34 : 26 без них у вас ничего не выйдет: • ·-------------------------------------------------------·-···------------···-····· 8 1 1
.. _·_.................. n.inux apt install build- essential dwarves pythonЗ libncurses - dev flex libssl - dev Ьс libelf - dev zstd gnupg2 wget -у Ьison После этого можно загрузить исходники ядра : wget https : // git . kernel . o rg / torvalds / t / linux-6 . 0-rc7 . tar . gz После загрузки распакуем архив: tar xvf linux~б . 0 - rc7 cd linux - 6 . 0-rc 7 / . tar . gz Скопируем текущую конфигурацию ядра в .config - чтобы вы использовали конфигурацию с включенными опциями , которые включены в вашем ядре . Иначе может оказаться , что какая-то опция будет выключена, и система бу­ дет работать некорректно после сборки ядра : ер - v / boot /config - $ (unarne - r ) . config Запустим программу конфигурации: rnake rnenuc onfig t\l'luм:/xвf 6 е e-rc.7 tetn-•l t:<it,ftt a111..Arrow k«ys n•vtg•te the ~f1U, <Enter> selects sub,ienus •«·> (or •f'IPty sl.lt>мnus ••••) , Ht9M.t9tttt-d \.t'tter~ •re i'totk.eys. Press\ng <V.., tnclud•s# <N> •:itc\ud•s, цt" f'IOdu\~rt z:es f••tuгes. Pres.s <Esc ...<Ese> t.o ex\t, <?> for Help, </> for St!aгch. Legend: [•] bui.lt-1..n ( ) t'l(Ctude-d <f-1;,o l'!Odu\e , > f'IO'duie- cap111>te IMЮФ№W!4HW ('"} М--Ь.t t k:ernel Processor ty~ and features ••• ,. ["} Jltitig•Hons for s~c:utat\ve eмecut\on vulner•b\.\\t1.es (HfW) P~ r 11.anagt-Nnt •nd дс Р I opt1on.s • • •> t us opttoos (PCI etc:,) ••• )' нn"ry E111Jt1t1.ons . ·•• ► ("' ) Hrtuf\\tllt\O'l'I ••• ,. . t:en.rat arch\tec:ture-de~nd•nt opt1.ons [•1 f.naЫe \oadab\e мdu\.e 5uppoгt • ••;. { •) 1' n1Ь\.~ tlм btcx.k t•у~г • .. ,. Extcu-tabl. ♦ f1.lt fornats •··~ №,юrу М!lna~ent optt<0ns [•] tц twoгktng support •· •~ ~v\ct Or\.vtrs ••• ,. Н\е syste"s • ·•· > $Atcur\ty optto"s • • • ► ·•· Crypt09r•ph\.<: API • .. ,. t \brary rourtnes ••·> Kitrne\ har::k\ng Рис. 3.2. ••• ► Конфигуратор ядра в Ubuntu 22.04
1 n..inux .................. . 1, 11\,1 \ "'41\\1111 . IШIIШ SI rpa Внесите изменения в конфигурацию ядра. Можете ничего не вносить, если просто хотите научиться перекомпилировать ядро. Обязательно (если вноси­ ли изменения) нажмите кнопку Save. Далее нужно отключить SYSTEM_REVOCAТION . Это можно сделать ко­ манд ами: scripts/config -- disaЬle SYSTEM REVOCATION KEYS make localmodconfig Построим сжатый образ ядра - он занимает меньше места на диске : make bzlmage Вывод будет примерно таким : SYNC include /co nfig /au to . conf.cmd _HOSTCC scripts/kconfig / conf . o HOSTLD scripts/kconfig/conf SYSHDR arch/x86/include/generated/uapi/ a sm/unistd_32 . h SYSHDR arch/x86/include/generated/uapi/asm/un i s t d_ 6 4. h SYSHDR arch/x86/include/generated/uapi/asm/unis t d_ x32 . h SYSTBL arch/x86/include/generated/asm/sysca lls _ 32 . h SYSHDR arch / x86 /i nclude/generated/asm / un is td_ 32_ ia32 . h SYSHDR arch / x86 /i nclude/generated / asm/unistd_64 x32.h После этого соберем и установим модули: make modules sudo make modules install Осталось установить ядро и обновить загрузчик : sudo make install sudo update - grub • ··------------------------··------ ----------···-··--······ ··· ·· · ··················-811
Я , 11ю l .i1111, ...................... t\.1nux Перезагружаем компьютер: reboot После загрузки введите команду : uname -а Вы должны увидеть версию ядра : Linux ubuntu2204 6 . 0 . 0 - rc7 Мы видим , что версия ядра изменилась на 6,0, Собственно, на этом все. В следующей главе мы поговорим о такой важной части при работе с ядром Linux как настройка загрузчика команда GRUB - чтобы вы понимали, что делает update-grub. • ............................. ------------... --- ----. ---. ---.. ---. ---. --------. ----. -.
Глава Загрузчик 4. GRUB2
Ядро 4.1. l,inux ...................... n..inux Загрузчики Linux Существует несколько за~узчиков 1 Linux. На сегодняшний день основным загрузчиком является GRUВ2, который устанавливается по умолчанию во всех современных дистрибупrnах Linux. Одним из самых "древних" загрузчиков является загрузчик давно уже не используется и GRUB (GRand Unified Bootloader). GRUB ему LILO (Llnux LOader). на смену пришел является более гибким загрузчи­ ком и "понимает" _ много разных файловых систем, в том числе ext2, ехtЗ, На смену Этот загрузчик FAT/FAT32, ReiserFS, XFS, BSDFS. GRUB пришел загрузчик GRUB2. Его особенности - очень запу­ танный и неудобный файл конфигурации, но время не стоит на месте, и если вы хотите использовать последние новинки в мире файловых систем Linux, ext4 и загрузку с LVM, вы должны использовать GRUB2 . Также GRUB2 подцерживает UEFI, но это пригодится вам, только если вы - счастливый обладатель жесткого диска объема 2 Тб . или больше. а именно файловую систему Собственно, GRUB2 сейчас устанавливается во всех современных дистрибу­ тивах, и нет смысла возвращаться на GRUB. Если возникнет необходимость, вы можете вернуться на обычный GRUB, установив пакет grub-legacy, но такая возможность есть только для платформы х86. •
n..inux ................. . 4.2. Конф и гурацио нные В каталоге фа йл ы /etc/grub.d хранятся шаблоны , определяющие настройки Также некоторые его параметры хранятся в файле шаблонам из mkconfig /etc/grub.d и файлу /etc/default/grub GRUB2. /etc/default/grub . По программой /usr/sЬin/grub­ создается рабочий конфигурационный файл /Ьoot/gruЬ/grub . cfg, который по задумке разработчиков GRUB2 вы не должны редактировать вручную. Поэтому есть две стратегии настройки GRUB2. Первая заключается в непо­ средственном редактировании файла /Ьoot/gruЬ/grub.cfg. Загрузчику все равно , кто или что отредактирует этот файл - GRUB2 или вы или программа grub-mkconfig . Вторая заключается в редактировании файлов из катало­ га /etc/grub.d и файла /etc/default/grub. После чего вы будете должны ввести команду grub-mkconfig для создания файла /Ьoot/gruЬ/grub . cfg по заданным вами настройкам. Чтобы решить , какая из стратегий для вас лучше, нужно знать формат и со­ держимое всех этих файлов. Начнем с основного файла конфигурации, кото­ рый сложнее и длиннее файла конфигурации обычного Листинг 4.1. GRUB ( см. лист. 4.1 ). Файл конфигурации /boot/gruЬ/grub.cfg # Не редактируйте # Он автоматически # # из # этот файл вручную ! # генерируется программой grub- mkconfig /etc/grub .d и на'стройкам из /etc/de fault /g rub по ш абло на м ### НАЧАЛО файла /etc/grub . d/OO_header ### if [ - s $prefix/grubenv ] ; then load env fi # Загрузочная метка по умолчанию set default= " O" if [ " ${prev_saved_entry} " ] ; then set saved_entry= " ${prev_saved_entry} " save_env saved_ entry set prev_saved_ entry= save_env prev_ saved_entry • ·················································································· C I I
}l , 11ю l,i1111, ......-................ n.1nux set boot once =true fi function savedefault { if [ -z " ${boot_once} " ]; then saved_entry= " ${chosen} " save env saved_entry fi function insmod insmod insmod insmod load video vbe vga . video bochs video cirrus i nsmo~ part_msdos insmod ext2 # Корневое устройство set root= ' (hdO , msdosl) ' search --no- floppy - -fs-uuid -- set=root Ь7300e54 -fff5-4f31 - 8002 -Ьea43c64f344 if loadfont /usr/share/gruЬ/unicode . pf2 ; then set gfxmode=640x480 load video insmod gfxterm insmod part_msdos insmod ext2 set root= ' (hdO,msdosl) ' search - -no-floppy - -fs - uuid - - set = root b7300e54 - fff5-4f31 - 8002 bea43c64f344 set locale dir=($root)/boot/gruЬ/locale set lang=ru_RU insmod gettext fi t erminal output gfxterm set timeout=S ### КОНЕЦ файла /etc/grub.d/00 header ### ### НАЧАЛО файла /etc/grub .d /05 debian theme ### insmo d part msdos insmod ext2 # Корневое устройство set root= ' .(hdO , msdosl) ' search --no-floppy - -fs -uuid --set=root Ь7300e54 -fff5-4f31 - 8002 -bea43c64f344 insmod png if background_image / usr/share/images/desktop- base/joy- grub.png ; then set color normal=white/Ыack set color highlight=Ыack/white - , . . . ................... . .......... . .......................... . .. . . .. . . ............... .
f.t1пux .. _..... _.. _____ .. l .ic\ lbl -+. Ja, р~ l'lllh" {;1н В2 else set menu_ colo r_n ormal=cyan / Ьlue se t menu co l or_h ig h light=white / Ьlue fi ### КОНЕЦ файла /etc/grub . d/OS_debi an_t heme ### ### НАЧАЛ О файла /e t c/grub . d / 1 0 linux ### # Содержит главную загрузочную метку . Далее мы ее рассмотрим подробнее menue ntry ' DeЬian GNU/Linux, Linux 5.2.0- 4- amd64 ' --class deЬian --class gnulinux -- class gnu -- class os { load video insmod gzi o insmod p&rt msdos insmod ex t 2 se t root= ' (hdO, msdosl) ' search --n о -П орру -- fs - uuid --s et= r oo t b7300e54 - fff5 - 4f 3 1-8002bea43c64f344 echo 'Загружается Linux 5 . 2.0 - 4 - amd64 ... ' linux / boot /vmlinuz-5. 2 . 0-4-amd6 4 root=UUID=b 7300e54 - fff 5- 4f31-8002bea43c64f344 r o initrd= /insta ll /gtk/i nitrd. gz q ui et echo' ' Загружается начальный ramdisk ... ' initrd /boot/initrd . img-5. 2 . 0 -4- a md64 menuentry 'Debian GNU/Linux , Lin ux 5 . 2 . 0 - 4 - amd64 (recovery mode)' -- class debian -- c l ass gnu-linux -- class gnu -- class o s { load video insmod gzi o insmod part msdos i nsmod ext2 set root= ' (hdO ,msdosl) •· search --n о -П о рру --fs-uui d -- set=root b7300e54 - fff5 - 4f31 - 8002 bea43c64f344 echo ' Загружается Linux 5.2 . 0 -4-amd64 . .. ' linux / boot/vmlinuz-5. 2 . 0-4- a md 64 root=UUID=b7300e54 - fff5 - 4f31-8002 bea43c64f344 r o single initrd=/install/gtk/initrd . gz echo ' Загружается начальный ramdisk . .. ' initrd /boot/ initrd . img-5. 2 . 0 - 4 -amd64 } ### КОНЕЦ / etc / grub.d / 10 linux ### ### ### НАЧАЛ О /etc/ grub . d /20_ linux_xen ### / etc / grub.d /20 linux_xen ### КО НЕЦ ### НАЧАЛ О /etc/grub . d /20 _memtest 86+ ### # Метка для mem test86 - пр о граммы для пр о верки menuentry " Memory test (memt es t 86+ ) " { insmod part_ msdos insmod ex t 2 set r oo t=' (hdO,msdosl )' , _ памяти --- ------. -----. . --.... .. . . . . . --. -...... -....................................... .
Я1tро [,inux ...................... rt.iпux search -- no - floppy -- fs - uuid -- set=root b7300e54 - fff5 - 4f31 - 8002 bea43c64f344 linuxlб /boot/memtest86+ . Ьin menuentry " Memory test (memtest86+ , serial console 115200) " { insmod part_msdos insmod ext2 set root= ' (hd 0 , msdosl) ' search -- no - floppy -- fs - uuid -- set=root b7300e54 - fff5 - 4f31 - 8002 bea43c64f344 linuxlб /boot/memtest86+ . Ыn console=ttyS0 , 115200n8 menuentry " M~mory test (memtest86+ , experimental multiboot) " insmod part_msdos insmod ext2 set root= ' ( hd0 , msdos 1) ' search -- no - floppy --fs - uuid -- set=root b7300e54 - fff5 - 4f31 - 8002 bea43c64f344 multiboot /boot/memtest86 + multiboot . Ыn menuentry "Memory test (memtest86+ , serial console 115200 , e xpe rime ntal multiboot) " { insmod part_msdos insmod ext2 set root= ' (hd0 , msdosl) ' search -- no-floppy - - fs - uuid -- set=root b7300e54 - fff5 - 4f31 - 8002 bea43c64f344 multiboot /boot/memtest86+ multiboot . Ыn console =ttyS0 , 115200n8 ### # КОНЕЦ Далее ничего /etc/grub . d/20_memtest86+ ### этот файл я немного сократил , поскольку дальше в нем нет интересного Файл огромный и его синтаксис напоминает синтаксис Ьаsh-сценариев. Если вы просмотрели этот конфигурационный файл, то вы уже догадались, что делает программа лога /etc/grub.d grub-mkconfig: она собирает воедино все файлы из ката­ (кстати, в листинге 4.1 перечислена большая часть из этих файлов) и вносит в общий конфигурационный файл из Основная запись из всего лисцшга 4.1 - это запись /etc/default/grub. menuentry. Именно в та­ ких записях описываются элементы меню загрузчика GRUВ. • ..................... .. .. .......... ................................................ ,
1, 1ава 4. Jai р~ n.1nux ................. . 1•1111, CIHiВ2 menuentry ' Debian GNU/Linux , Linux 5 . 2 . 0-4-amd64 ' --class debian --class gnulinux -- class gnu -- class os { load video insmod gzio insmod part msdos insmod ext2 set root= ' (hdO , msdosl) ' search -- no - floppy -- fs - uuid -- set=root b7300e54 - fff5 - 4f31 - 8002 bea43c64f344 echo ' Loading Linux 5 . 2 . 0- 4- amd64 .. . ' linux / boot /vmlinuz - 5 . 2 . 0- 4- amd64 root =UUID=b7300e54 - fff5 - 4f31 - 8002 bea43c64f344 ro initrd=/install/gtk/initrd . gz quiet echo ' Loading initial ramdisk ... ' initrd /boot/initrd . img - 5 . 2 . 0- 4- amd64 В одинарных кавычках после menuentry указывается название загрузоч­ ной метки . Далее идут параметры, которые вообще можно не указывать и от этого DeЬian загружаться не перестанет. В фигурных скобках конфигурация. Директива load_video, load_video - - основная это ни что иное , как вызов функции которая также описана в этом файле конфигурации. Функция вставляет некоторые модули (команда insmod), необходимые для работы графического режима. Обратите внимание, что команды не модули ядра Linux, а модули GRUB2, insmod загружают которые находятся в каталоге /Ьооt/ grub. Внутри {} можно использовать команду echo для обозначения различных этапов загрузки, что и сделано в нашем примере. Можете отказаться от echo, на загрузку это никак не повлияет. Основные команды - это linux и initrd. Первая указывает путь к ядру Linux и задает параметры ядра. В нашем случае параметр ядра root указывает устройство , на котором находится корневая файловая система . Устройство указано в виде UUID. UUID-имeнa очень удобны. Представим, что у вас есть один жесткий диск SATA и два контроллера. Если вы подключите его ко вто­ рому контроллеру, обычное имя изменится (например , было /dev/sda, а стало /dev/sdb ), а UUID-имя - нет. При желании , вы можете указать имя в старом формате, например, root=/dev/sdal. Параметр ядра ro задает монтирование корневой файловой системы в режиме "только чтение" (это нормально, поз­ же она будет перемонтирована), параметр ядра quiet задает initrd - задает файл RarnDisk, а последний "тихую" загрузку ядра , при которой будут выво­ диться только самые важные сообщения . • ................................................................................... . .
Я . 1ро l.inux initrd Команда Теперь задает рассмотрим Листинг # # # # ______________________ n.inux 4.2. Файл файл Для файла получения к файлу initrd . /etc/default/grub ( листинг 4.2) /etc/default/grub После редактирования обновления путь этого файла запустите команду ' update - g r ub ' для /boot/gruЬ/gru b.cfg. полной информации об этом файле введите команду info -f grub - n ' Simple configuration ' # Загрузочный элемент (menuentry по умолчанию) GRUB DEFAULT=0 # Таймаут GRUB TIMEOUT=5 # Задает название дистрибутива , не изменяйте эту строку GRUB DISTRIBUTOR='lsb release -i - s 2> /dev/null 11 echo # Параметры ядра Linux по умолчанию GRUB_CMDLINE LINUX_DEFAULT= " quiet " # Еще одна строка для задания параметров я дра GRUB_CMDLINE LINUX= " initrd=/install/gtk/initrd . gz " # Раскомментируйте эту строку , #GRUB TERМINAL=console если вы хотите отключить графический режим # Разрешение в графическом режиме # Вы можете использовать только те режимы , которые # поддерживает через VBE . Просмотреть список # таких режимов можно с помощью коман ды 'vbeinfo ' #GRUB GFXMODE=640x480 # Раскомментируйте эту строку , если # использовать UUID - имeнa устройств #GRUB DISABLE LINUX UUID=true # Раскомментируйте , если хотите запретить #GRUB DISABLE RECOVERY= " true " # Раскомментируйте , если хотите #GRUB INIT TUNE= " 480 440 1 " Как видите , параметры из файла вы не DeЬian' ваша видеокарта хотите генерирование меток восстановления получить гудок при /etc/default/grub понятны загрузке GRU8 и не нуждаются в особых комментариях . Но в нем мы узнали о еще одной команде grub . Так какую из них использовать - update- update-grub или grub-mkconfig? • са - .. -.-.-. ---------.--.. ----.. --.------------- ------.---.. -. -- --------------------.
n.iпux ................. . J j шва 4. ·1аrрузчик (;RUB2 На самом деле это почти одна и та же команда. Дело в том , что команда grub- mkconfig по умолчанию выводит конфигурацию GRUВ2 на экран , поэтому, чтобы она записалась в файла /Ьoot/gruЬ/grub.cfg, запускать ее нужно так: sudo grub -m kconfig > / bo o t / gruЬ/grub.cfg Или же вы можете ввести команду мое. Другими словами, команда update-grub, которая сделает то же са­ update-grub - это сценарий, который вызы­ вает только что приведенную команду. Как по мне, то использовать команду update-grub удобнее. Так какую стратегию GRUВ2 использовать? Редактировать шаблоны и пара­ метры или сразу конфигурационный файл? Если вы работаете за компьюте­ ром в гордом одиночестве и нет и не предвидится других администраторов , то тогда можете выбрать ту стратегию, которая вам больше нравится. Если же есть или планируются другие администраторы, то нужно редакти­ ровать шаблоны и параметры вместо редактирования конфигурационного файла вручную. Дело в том , что если вы внесете изменения непосредствен­ но в конфигурационный файл, а потом другой администратор захочет из ­ менить какой-то незначительный параметр, например, добавить гудок при загрузке GRUВ2 , то команда update-grub перезапишет все сделанные вами изменения . 4.3. Выбор метки по умолчанию Как правило, даже если у вас установлена одна только Linux, у вас будет несколько загрузочных меток (несколько записей menuentry). Выбрать метку по умолчанию можно с помощью параметра GRUВ _ DEFAULТ. Нумерация меток начинается с О, то есть первой метке соответствует значение О. После того, как вы установите другой номер метки по умолчанию нужно ввести команду update-grub и перезагрузить систему. Другими словами, последовательность такая: редактируем файл grub, изменяем update-grub . • значение параметра GRUB DEFAULT /etc/default/ и вводим команду .. . . ----------------- ---- ----------.... -- .... ----.. --.. --... -... --.. ---. -. -.. --... -
Я , 1р11 lj1нix 4.4. ...................... fl1nux Загрузка Windows Как правило, если имеете дело с производственное применение Linux Linux, то упор делается на серверы и прочее Linux, однако вдруг вы захотите установить на домашний компьютер , скорее всего , ей придется "сожительство­ вать" с Windows, Чтобы добавить возможность загрузки тировать файл /etc/grub.d/40_custom Windows из GRUB2, нужно отредак­ и добавить в него следующие строки: menuentry " Windows (оп / dev / sdal) " insmod part_ msdos insmod ntfs set root= ' (hdO,msdosl)' search -- no - floppy -- fs - uuid -- set UUID drivemap - s (hd O) $ {r o ot } chainloader +1 Здесь Windows находится на /dev/sdal и адрес этого раздела указывается в set root. Значение UUID нужно заменить на UUID вашего Windows-paздeлa. О том, как "вычислить" UUID раздела, мы поговорим, возможно, в другой главе. Остальные параметры можете оставить без изменения (еще не забудь­ те исправить hdO в drivemap, если Windows установлена не на первом жест­ ком диске). 4.5. Пароль загрузчика GRUB2 Загрузчик GRUВ позволял только установить пароль загрузку определенной метки. Загрузчик GRUB2 - или общий, или на более гибкий в это~ плане, поскольку вы можете настроить не только пароли, но и логины. Также есть минимальная система разграничения прав доступа. Итак, в GRUB2 есть суперпользователь, который может редактировать загрузочные метки. Существует возможность восстановить пароль тем передачи ядру параметра фигурацию GRUB2. init. Но root пу­ для этого нужно отредактировать кон­ Если вы установите пароль суперпользователя, то изме­ нить конфигурацию загрузчика вы сможете только после ввода этого пароля . - • ----- ....... ····- . ................ ··-·. ---· ..... ·-· ... . ....... · ·-- ------- ·--· ----· .
t\.inux ................. . Также в GRUB2 есть обычные пользователи, которые имеют право только выбир8;ТЬ загрузочную метку. Они не имеют права редактировать конфигу­ рацию загрузчика. В принципе, можно обойтись одним паролем суперполь­ зователя, но при желании может довольно гибко разграничить права GRUB2 пользователей. Давайте сначала добавим пароль суперпользователя. Для этого в файл grub.d/00_header добавьте /etc/ строки: set s uperuser s =" main_ admin " p as swo r d ma ih admin 123456789 Первая команда задает суперпользователя main_admin, а вторая - задает для admin, root и него пароль . Старайтесь избегать общепринятых имен вроде т.д. Так у злоумышленника, который хочет изменить конфигурацию GRUВ2 будет больше неизвестных данных. Пароль пока в незашифрованном виде и это не очень хорошо. Поскольку если загрузиться с LiveCD или LiveUSB, то его можно будет увидеть. Позже я покажу, как зашифровать пароль. Обычные пользователи задаются инструкцией password, например: passwo r d me 12345 По сути main _ admin - тоже был бы обычным пользователем , если set superusers, которая делает его суперпольз овател ем. бы не инструкция Представим, что у нас есть следующие строки: set superusers= " main_admin " p assword main_adm i n 123456789 p assword me 12345 Пользователь main_admin может загружать операционные конфигурацию GRUB2. Пользователь те может системы и редак­ тировать только загружать операционные системы. - Если вы хотите, чтобы определенные метки могли загружать только опреде­ ,. л енные пользователи, добавьте к menuentry параметр --users: - .... -- . --... - ... -.... --.. --... -.. -. -------.. ---. - . -- ---. - ----- . -- ....... -......
Я . 1ро Linux .. ____________ .. _.. _.. n..inux menuentry " Windows " -- users me { insmod part msdos insmod ntfs set root= ' (hdO , msdosl) ' search -- no - floppy - -fs - uuid -- set UUID drivemap - s (hdO) ${root} chainloader +1 Теперь зашифруем пароль . Введите команду: grub-mkpasswd- pbkdf2 Программа запросит пароль , зашифрует его и выведет на экран его кэш. Вы увидите что-то подобное: grub . pbkdf2 . sha512 . 10000 . 9290F727ED06C38BA 4549 EF7DE25C F5 6 42659 211B7FC076F2D27080136.887CFF169EA83D5235D80047 42AA7D6187 A41E 3 1 87DFOCE14E256085ED97A979080136 . 887CFF169EA8335235D8 0 04 242AA706 187A41E3187DFOCE14E256D85ED97A97357AAA8 FF OA387 1AB9EEFF458392 F4 62F495487387F685B7472FC6C29E293FOAO Данный хэш нужно указать вместо пароля пользователя. Однако вместо ин­ струкции passwd нужно использовать password_pbkdf2. Например: password_pbkdf2 me grub . pbkdf2.sha512 . 1000 0. 9290 F727 ED0 6C38 BA4 549EF7DE25CF5642659211B7FC076F2D27080 1 36 . 887CFF1 69 EA83D523 5D8 0 04742AA706187A41E3187DFOCE14E256D85ED97A979080 1 36 . 887CF F169EA8 335235D8004242AA7D6187A41E3187DFOCE14 E256D85 ED97A9735 7AAA8 FF OA 3871AB9EEFF45839ZF462F495487387 F685B7472FC6C29 E293 FOAO После изменения файлов из каталога upgrade-grub для /etc/grub.d не забудьте ввести команду обновления основного файла конфигурации. • - - - ---------------·---------------------·-------------- ----- -- --- -------------------·
1; 1а11а 4. t\.1nux ................. . 4.6. Ja1 ру 1•11ш (; IHIН2 Установка загрузчика Команда установки загрузчика такая же, как и в случае с GRUВ: # / sbin / grub-install <устройство> Например: # / sbin / grub - install / dev / sda Поскольку GRUB2 у вас уже установлен, вряд ли вам придется вводить эту команду. Исключение может составить разве что переустановка всей систе­ мы, которая перезапишет загрузочный сектор своим загрузчиком. Поэтому вам придется загрузиться с LiveCD, выполнить корневой системы и ввести команду grub-insta/1 для вашей старой chroot для установки загрузчика GRUB2. 4. 7. Система инициализации После своей загрузки ядро передает управление систе.ме инициализации. Цель этой системы - выполнить дальнейшую инициализацию системы. Са­ мая главная задача системы инициализации - запуск и управление систем­ ными службами. Служба (сервис, де.мон) специальная программа, выполняющаяся в фоно­ - вом режиме и предоставляющая определенные услуги (или, как говорят, сер­ вис - отсюда и второе название) . Что превращает обычный компьютер, скажем, в FТР-сервер? Правильно , за­ пущенная служба FTP - тот же ProFTPD или подобная. Вы можете устано­ ProFTPD и настроить ее на автоматический запуск системой вить программу инициализации. Тогда при каждой загрузке наш компьютер будет превра­ щаться в FТР-сервер. Аналогично и с другими сервисами -достаточно уста­ новить определенную программу, чтобы превратить компьютер в веб-сервер или почтовый сервер. Но стоит вам отключить ее и компьютер уже прекра- • . . ........ .. - - - - - - - - . - .... - - - - - - - - . - - - . - - - - . ... .. ·- .. ..... - - - - - - - - - - - - -· - - - - - - . - - ...
...................... t't.1пux И IJIO l,i1111\ щает предоставлять обеспечиваемые программой услуги, следовательно, превращается в самый обычный компьютер. В мире Linux существовало очень много разных систем инициализации init, upstart, init-ng. Все их рассматривать уже нет смысла, поскольку в совре­ менных дистрибутивах используется современная система инициализации systemd. systemd - подсистема инициализации и управления службами в фактически вытеснившая в 2010-е годы традиционную Основная ос?бенность Linux, подсистему init. интенсивное распараллеливание запуска служб - в процессе загрузки системы, что позволяет существенно ускорить запуск операционной системы. Основная единица управления типов модулей являются "службы" запускаемые и управляемые - аналог демонов средствами модуль, одним из - - наборы процессов, подсистемы и изолируемые контрольными группами. 4.7.1. Система инициализации Принцип работы systemd используется во многих современных дис­ Fedora, UЬuntu, CentOS и openSUSE. На данный трибутивах, в частности в момент - это самая быстрая система инициализации. Давайте подумаем, как можно ускорить запуск upstart -параллельно запускать службы. Linux? Можно пойти по пути Но параллельный запуск - хорошо. Нужно учитывать зависимости служб. Например, сервис жен многим другим сервисам. Пока сервис d-bus не всегда d-bus ну­ не будет запущен, нельзя запускать сервисы, которые от него зависят. Если сначала запускать основные сервисы и ждать, пока они будут запуще­ ны, а потом уже запускать службы, которые от них зависимы, особого выигрыша в производительности по сравнению с сервис d-bus init вы не увидите. Но если (или любой другой, от которого зависят какие-то другие серви­ сы) запускается долго, то все остальные службы будут ждать его. Как обойти это ограничение? При своем запуске службы проверяют, запу­ щена ли необходимая им служба, по наличию файла сокета. Например, в случае с d-bus -это файл /var/run/dbus/system_bus_sock~t. Если мы создадим со. кеты для всех служб, то мы можем запускать их параллельно, особо не - беспокоясь, что произойдет сбой какой-то службы при запуске из-за отсут­ ствия службы, от которой они зависят. Даже если несколько служб; которым ---------- ---- ----.. --- ----. --... --.. ---.. -------.. -... -.. --- -. ---. -. -.. -- -. ---_,
l .1 1.ша 4. n..inux ................. . нужен сервис d-bus, запустятся раньше·, чем сам сервис J:11 f))' 1•11ш (;IHIВ2 d-bus: ничего страш­ ного. Каждая из этих служб отправит в сокет (главное, что он уже открыт!) сообщение, которое обработает сервис d-bus после того, как он запустится. Вот и все. Но это не единственное "ухищрение", посредством которого осуществля­ ется ускорение запуска компьютера, инициализацию которого производит systemd. Эта система инициализации запускает только необходимые серви­ сы. Остальные же будут запущены по мере необходимости. Концепция от­ OS Х (там система инициализации называется launchd) и в Windows (концепция отложенного запуска служб). Так что решение не очень ложенного запуска используется и в других операционных системах например, в Мае новое, но зато проверенное. Основными функциями • systemd являются: Активация на основании сокетов - система инициализации systemd прослушивает сокеты всех системных служб. Сокеты передаются системным службам сразу после запуска сервцсов. Благодаря этому осу­ ществляется параллельный запуск сервисов. Также это позволяет переза­ пускать сервисы без потери любых отправленных им сообщений , то есть пока сервис перезапускается, отправленные ему сообщения накаплива­ ются, и он сможет их обработать после того, как будет запущен . • Активация на основании устройств - systemd может запустить опреде­ ленные службы, когда станет доступным определенный тип оборудова­ ния . Например, вы подключили Bluetooth-aдaптep, может быть запущен сервис Ыuetooth. • Активация на основании d-bus - служба инициализации может за­ пустить сервисы , которые используют d~bus для межпроцессного взаимо­ действия, например, когда клиентское приложение попытается связаться с системной службой . • Активация на основании путей - systemd может запустить службу, если изменится содержание каталога. • Управление точками монтирования и автоматическим монтирова­ нием -система инициализации отслеживает и управляет точками монти­ рования и автоматического монтирования. • Снимки системных состояний - благодаря этой возможности systemd - может сохранить состояние всех модулей и восстановить предыдущее состояние системы. - -· ... ---.. --.... ---... -........ -... --... -.. -... ---... -.. -. -. -. . --. -. ---. --. . -...
Ищю • l ,i1111x ..................... . ,n .lnux Параллелизация - systemd запускает системные службы параллельно благодаря активации на основании сокетов. Параллельная активация су­ щественно сокращает время загрузки системы. • Обратная совместимость с лизации SysV, SysV - поддерживаются сценарии · инициа­ что упрощает переход на systemd. Однако все устанавли­ ваемые в современных дистрибутивах пакеты служб уже адаптированы под systemd, поэтому не нужно надеяться, что во время установки пакета какого-то сервиса будут установлены SуsV-сценарии. Будут созданы фай­ лы, необходимые для запуска сервиса посредством systemd. 4. 7.2. Конфигурационные файлы systemd Обилие различных конфигурационных файлов systemd может ввести в сту­ пор даже бывалого линуксоида, не говоря уже о пользователе, который впер­ вые видит systemd. Когда я впервые познакомился с то)Iько одно желание - снести ее и установить systemd, у меня вместо нее init. Но мы было этого не будем делать. Чтобы разобраться со всеми файлами, нужно понимать, как работает эта система. В systemd используется концепция модулей (юнитов). Существующие типы модулей описаны в таблице Таблица 4.1. 4.1. Типы модулей системы инициализации Тип systemd Описание Служба (сервис, демон), которую нужно запустить. Пример имени модуля : network.service. Изначально systemd поддерSysV (чтобы управлять сервисами можно было, как при использовании init), но в последнее время в каталоге /etc/init.d систем, которые используют systemd живала сценарии service практически пусто (или вообще пусто), а управление сервисами осуществляется только посредством -- systemd • ---.---... --.. --... -.. -- -.. ---. -- -.. ---- . -... --.. ---- . --... -... --- .. -... -.... -.. --,
ft1nux ... ........... ·... . Цель. Используется для группировки модулей других типов. В target systemd нет уровней запуска, вместо них исполь- зуются цели. Например, цель multi-user.target описывает, какие модули должны быть запущены в многопользовательском режиме Снимок. Используется для сохранения состояния snapshot systemd. Снимки могут использоваться для перевода системы из одного состояния в другое, например, в состояние сна и про- буждение Точка монтирования. Представляет точку монтирования. Система инициализации mount systemd контролирует все точки монтирования. При использовании systemd файл /etc/fstab уже не главный, хотя все еще может использоваться для определения точек монтирования Автоматическая точка монтирования. Используется для automount монтирования сменных носителей - флешек, внешних жестких дисков, оптических дисков и т.д. Сокет. Представляет сокет, находящийся в файловой системе или в Интернете. Поддерживаются сокеты socket AF_ INET6, AF_ UNIX. AF _INET, Реализация довольно интересная. Например, если сервису кет service l .service соответствует соservice l .socket, то при попытке установки соединения с service l .socket будет запущен service l .service Устройство . Представляет устройство в дереве устройств . device Работает вместе с правила udev, udev: если устройство описано в виде то его можно представить в модуля • systemd в виде device path Файл или каталог, созданный где-то в файловой системе scope Процесс, который создан извне ··-····· ··· ·· ··· ···· ·-····················· ······································· -
И IIНI __ .................... n..iпux l , i,111 \ Управляет системными процессами , Представляет собой slice группу иерархически организованных модулей Представляет область подкачки (раздел подкачки) или файл swap подкачки (свопа) Представляет собой таймер системы инициализации timer systemd Модули хранятся в следующих каталогах: • /etc/systemd/system/ - обладает самым высоким приоритетом . Здесь со­ держатся модули, которые созданы и управляются системным адми ни­ стратором . • /run/systemd/system/ - модули, созданные во время выполнения. Приори­ тет этого каталога ниже , чем каталога /etc/systemd/system/, но выше , чем у /usr/liЬ/systemd/system . • /usr/liЬ/systemd/system/ - модули , которые установлены из пакетов . Типичный файл модуля типа Листинг 4.3. service приведен в листинге Типичный файл модуля типа 4.3 . service [Unit] Description=Daemon to detect crashing apps After =syslog . target [Service] ExecStart= / usr / sbin / ab r td Type=f o rking [Install] WantedBy=mul t i - user . target В секции Unit содержится общая информация о сервисе . Эта с екция есть и в других модулях , а не только в сервисах . • . ...................................... .......... - ... --- - ---· .............. ······ . . .
n.1nux ................. . Секция Service содержит информацию о сервисе. Параметр ExecStart опи­ сывает команду, которую нужно запустить. Параметр Туре указывает, как сервис будет уведомлять Секция Install об окончании запуска. systemd содержит информацию о цели, в которой должен запускать­ ся сервис . В нашем случае видно , что сервис будет запущен при активации цели multi-user.target. Вы можете использовать эту "болванку" для написания собственного серви­ са, который потом нужно поместить в файл /etc/systemd/system/имя _ cepвиca. service. После этого нужно перезапустить саму новом сервисе: systemd, чтобы она узнала о . # systemctl daemon - reload Цели 4.7.3. Теперь поговорим о целях . Файлы целей пировки вместе других юнитов модуль цели systemd graphical.target, который *.target предназначены для груп­ через цепочку зависимостей. Так, используется для запуска графическо­ го сеанса , запускает системные службы GDM (файл gdm.service) и Accounts Service (accounts-daemon.service), а также активирует цель multi-user.target. В свою очередь, цель multi- user.target запускает другие системные службы, например , D-Bus (dbus.service) и активирует другие цели вроде basic.target. В systemd имеются предопределенные цели , которые напоминают стандарт­ ный набор уровней запуска. Некоторые цели называются ших пользователей runlevelN.target, init на systemd, а именно: • poweroff.target (runlevelO .target) - чтобы упростить переход быв­ завершение работы и отключение системы; • rescue.target (runlevell.target) - однопользовательский режим, среда вос­ становления; • multi- user.target'(runlevel2.target, runlevelЗ.target, runlevel4.target) - много­ пользовательский режим, без графического интерфейса; • ············································································ ······ -
И , 1р11 l .illll\ ...................... rtinux • graphical.target (runlevel5.target)- многопользовательский режим с графи­ ческим интерфейсом; • reboot.target (runlevelб.target) - завершение работы и перезагрузка системы. Управление службами осуществляется с помощью программы systemctl. Подробнее о службах мы, возможно, поговорим в другой главе, а пока раз­ беремся, как использовать • systemctl halt - systemctl для завершения работы системы: останавливает систему; • systemctl poweroff • systemctl reboot - выключает систему; перезагружает систему. Многим пользователям будет удобнее использовать старые команды poweroff и reboot. ha/t, Но все же теперь вы знаете, qто есть альтернативные спо­ собы завершения работы. 4.8. Управление systemd сервисами при использовании При использовании системы инициализации systemd управление службами systemctl. Команда systemctl ис­ в таблице 4.2 представлены не все ее осуществляется посредством программы пользуется для разных целей, поэтому параметры, а только те, которые имеют отношение к сервисам. Таблица 4.2. Параметры программы systemctl Параметр Описание start <имя.service> Запускает сервис stop <имя.service> Останавливает сервис • ............................................ ................ ..................... ... •
I J 1aнa n..inux _________________ _ -+. Загр~иш, CRtlB2 restart <имя.service> Перезапускает сервис try-restart <имя.service> Перезапуск сервиса только, если он запущен reload <имя.service> Перезагружает конфигурацию сервиса status <имя.service> Отображает подробное состояние сервиса is-active Отображает только строку <имя.service> пущен) или list-units --type service --all active (сервис inactive (остановлен) за- Выводит состояние всех сервисов Включает сервис (обеспечивает его автомати- еnаЫе <имя.service> ческий запуск) Отключает сервис (сервис не будет автомати- disaЫe <имя.service> чески запускаться при запуске системы) reenaЫe <имя.service> list-unit-files --type service Деактивирует сервис и сразу его использует Выводит список всех сервисов и сообщает, какие из них активированы, а какие - нет Примеры: # systemctl start httpd.service # systemctl stop httpd Первая команда запускает сервис Обратите внимание, что Бывалые пользователи ".service" Linux httpd (веб-сервер), вторая - останавливает. можно не указывать. сразу заметят удобства. Ран-ее, чтобы отклю­ чить службу на определенном уровне запуска, нужно было удалить ее сим­ волическую ссылку из определенного каталога. Аналогично, чтобы служба запускалась на определенном уровне запуска (например , в графическом ре­ жиме), нужно было создать символическую ссылку. Сейчас всего этого нет, а есть только команды епаЫе и disaЬle, что стало гораздо удобнее . • .------ ---------------------- ---------------- ------------- ------------------------ -
Глава 5. Как ядро управляет процессами
Я , 1ро l,i1шx 5.1. ...................... n..iпux Что такое процесс Процесс-это код (программа), находящийся в состоянии выполнения. Также процесс - это не только исполняемый программный код, а еще и на­ бор ресурсов (открытые файлы и сигналы, ожидающие обработки, внутрен­ ние данные ядра, один или несколько потоков выполнения tion)), а также сегмент данных программы (data section), (threads of execu- который содержит глобальные переменные. Потоки (threads), выполнения кода, которые часто называют просто потоками представляют собой объекты, выполняющие определенные дей­ ствия внутри процесса. В каждом из потоков содержатся уникальный счет­ чик команд (program counter), стек пjюцесса и набор регистров процессора. Планировщик ядра на самом деле управляет выполнением отдельных потоков, а не процессов. В традиционных Uniх-подобных операционных системах каждый процесс содержал только· один поток. Но в современных системах многопоточные программ1~r (т.е. программы, в которых запускается более одного потока выполнения команд) используются довольно часто. - • . . . .. -.... --.. ---.. --·. ---. ---.. ---. ---. ·- -.. - -.. --.. -. -. ---.. --.. ---. ·- -· .. -... --.. •
! ~ шва n..inux .................. . 5. Как я . 1ро ~прав.1яс1 11ронсссаш1 Процессы в современных ОС предусматривают наличие двух виртуальных ресурсов: виртуалыюго процессора Благодаря VCPU (VCPU) и виртуальной памяти (VRAM). для процесса создается иллюзия, что они монопольно ис­ пользуют весь компьютер, не смотря на то, что физический процессор могут использовать сотни других процессов . VRAM позволяет процессу распреде­ лять оперативную память компьютера и управлять ею так, как будто он один владеет всей памятью в системе. Сама по себе программа процессом не является. Процесс - это выполняюща­ яся программа и набор ресурсов . Может существовать несколько процессов, выполняющи:х одну и ту же программу. Также несколько процессов могут совместно использовать одни и те же ресурсы, такие как открытые файлы или адресное пространство . Процесс начинает существовать с момента соз­ дания. В операционной системе с системного вызова fork() , Linux существование процесса начинается который создает новый процесс путем полного копирования уже существующего . Процесс, вызвавший fork(), называется порождающим , или родит ел ьским (parent), рожденным, или дочерним Родительский процесс после этого про­ (child). а новый процесс именуют по­ должает свое выполнение , а дочерний начинает выполняться с одного и того же места - с момента возврата из системной функции возврат из системной функции fork() fork(). В результате выполняется из ядра дважды: один раз в родительском процессе, а второй раз - в порожденном . Если в одном из процессов нужно выполнить другую программу (не поро­ дить новый процесс этой программы, а именно вызвать другую программу), то нужно использовать функцию ехес(), которая создает новое адресное про­ странство и загружает в него новую программу. В современных ядрах функция fork() Linux на самом деле реализована через вызов системной функции clone(). Выход из процесса осуществляется с помощью функции exit(), которая за­ вершает выполнение процесса и освобождает все занятые им ресурсы. Роди­ тельский процесс может выдать запрос о состоянии завершенных дочерних процессов с помощью вызова системной функции одному процессу подождать завершения wait4(), другого которая позволяет указанного процесса. После завершения процесса он переводится в специальное состояние зомби (zombie), которое используется для представления завершенного процесса до того момента, пока порождающий его процесс не вызовет системную функцию • wait() или waitpid() . ... . . . . . . . . . . . . . . . . .. . . . . . . . . ... . . . . . . . . . . . .. . . . . . . . . . . . .. . .. . . . . .. . . ... . . . . . . . . . . -
Я , 1ро 5.2. l.i1111x ...................... n..inux Структуры , связанные с процессами 5.2.1. Список задач и структура процесса Список процессов хранится в ядре как двусвязный циклический список, ко­ торый называется списком задач. Каждый элемент этого списка описывает один запущенный процесс и называется дескриптором процесса , Дескрип­ тор процесса имеет тип <linux/sched,h>, task_struct, а сама структура определена в файле Структура довольно объемна и полное описание ее полей можно найти по адресу : https ://docs, huihoo,com/doxygen/linuxlkernel/3, 7/s tructtask_ s truct. html Посмотрите на рис , задач (task list), 5, 1, На нем показано, что представляет собой список Это двусвязный циклический список, элементами которого являются структуры типа task_struct. atruct tuk..atruct atruct tt1•k..•truct unsign.ed long state; lnt pdo; UAsigned long ро11су; struct tasl(_s1n.Юt •parent: struct llst_head tasks; process descriptor pkl...J pid; г the task 11st Р41с. 5.1. Список задач Каждый процесс динамически размещает структуру struct task_struct. Linux, симальное количество процессов, которое может быть создано в ничивается только объемом физической памяти и равно: Мак­ огра­ • - - - ....................................... ·-··· ----- ·- ---- ... ·-·- ·- -- .. -. --··· .... .
l . 1,1н,1:, Kai-: s1.1p11 ~щ1ав. 1wt>1 111ю11ссса\111 ainux ------------------- max threads mempages / что для архитектуры Например , на машине (THREAD_SIZE/PAGE SIZE) / 2; IA32 означает, как правило, num_physpages/4. с 2GB памяти, возможно создать 128k потоков. Кро­ ме того, этот предел может быть изменен в процессе исполнения, передачей значения КERN_МАХ_THREADS в вызове procfs: sysctl(2), • или через интерфейс # cat / proc / sys/kernel/threads - max 32764 # echo 100000 > /proc/sy s /kernel / threads-max # cat /proc/sys/ke rnel /thread s-max 100000 # gdb -q vmlinux /proc/kcore Core was generated Ьу ·воот_IМАGЕ=240 ас18 r o root=306 video=matrox : vesa : 0xllB '. #О О хО in ?? () (gdb) р max_threads $1 = 100000 Множество процессов в Linux-cиcтeмe представляет собой совокупность структур struct task_struct, которые взаимосвязаны двумя способами : • 1. Как хеш-массив, хешированный по 2. Как кольцевой двусвязный список, в котором элементы ссылаются друг pid на друга посредством указателей р-> next_task и р->prev_task. Хеш-массив определен в include/linux/sched.h как pidhash: #define PIDHASH_SZ (4096 >> 2) extern struct task_struct *pidhash[PIDHASH_SZ] ; #define pid_hashfn (х) ( ( ( (х) » 8) л (х)) & (PIDHASH_SZ - 1)) Задачи хешируются по значению pid, вышеприведенной хеш-функцией, которая равномерно распределяет элементы по диапазону от О до 1. Хеш-массив PID_ MAX- используется для быстрого поиска задачи по заданному с помощью inlinе-функции find _task_Ьу_pid(), определенной в include/linux/ sched.h: • pid .-. --. ----------------------. ----------------------- ----------------· ----------- ---
Я . 1ро l,i1111x ...................... n..inux static inline struct task_struct *find_task_by_pid(int pid) { struct task_struct *р , **htaЫe = &pidha sh [pid_hashfn(pi d)] ; f o r(p = *htaЫe ; р && p - >pid != pid; р = p - >pidha sh_nex t); return р ; Задачи в каждом хеш-списке (т.е . хешированные с тем же самым значением) связаны указателями p->pidhash_ next/pidhash_pprev, которые используются hash_pid() и unhash_pid() для добавления/удаления заданного в/из хеш-массив . Делается это под блокировкой (spinlock) tasklist_ функциями процесса lock, полученной на запись. Двусвязный список задач организован таким образом, чтобы упростить на­ вигацию по нему, используя указатели p->next_task/prev_ task. Для прохож­ for_each_task() из дения всего списка задач, в системе предусмотрен макрос include/linux/sched.h: #define for _ each task(p) != &init task ; ) \ for (р &init task (р p->next_task) Перед использованием for_each_task() необходимо получить блокировку tasklist_lock на чтение. Примечательно, что for_each_task() использует init_ task в качестве маркера начала (и конца) списка- благодаря тому, что задача с pid=O всегда присутствует в системе. Функции, изменяющие хеш-массив и/или таблицу связей процессов, особенно fork(), exit() и ptrace(), должны получить блокировку (spinlock) tasklist_lock на ЗАПИСЬ. Что особенно ин­ тересно - перед записью необходимо запрещать прерывания на локальном процессоре, по той причине, что функция send_ sigio(), при прохождении по списку задач, захватывает tasklist_lock на ЧТЕНИЕ, и вызывается она из kill_fasync() в контексте прерывания . Однако если требуется доступ только для чтения , запрещать прерывания нет необходимости. Теперь, когда доста­ точно понятно представлено как связаны между собой структуры можно перейти к рассмотрению полей В других версиях UNIX task_struct, task_ struct. информация о состоянии задачи разделяется на две части: • В одну часть выделяется информация о состоянии задачи (называется ... 'proc structure', которая включает в себя состояние процесса, информацию планировщика и пр.) и постоянно размеща·ется в памяти; • .. . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . .. . . . . . . . . . . . . . .. . . . . . . . .. . . .. . . . . . . . . . . . . .. . . .. .
) 1 1ава 5. Ка1, s1 tpo ~••р:111. 1щ•1 Щ)1щсt·са~111 t'.l1nux .................. . • Другая часть, необходима только во время работы процесса ('u area', кото­ рая включает в себя таблицу дескрипторов, дисковые квоты и пр.). Единственная причина такого подхода - дефицит памяти. Современные опе­ рационные системы (не только Linux, но и другие, современная FreeBSD например) не нуждаются в таком разделении и поэтому вся информация о состоянии процесса постоянно хранится в памяти. 5.2.2. Поле Состояния процесса state структуры task_struct объявлено как: volatile long state ; /* -1 unrunnaЫe , #define TASK RUNNING О #define TASK INTERRUPTIBLE 1 #define TASK UNINTERRUPTIBLE 2 #define TASK ZOMВIE 4 #define TASK STOPPED 8 #define TASK EXCLUSIVE 32 Спецификатор volatile в объявлении О p->state runnaЫe, >О stopped */ означает, что это поле может изменяться асинхронно (в обработчиках прерываний): • TASK_RUNNING - указывает на то, что задача "вероятно" находится в очереди запущенных задач (runqueue). Причина, по которой задача мо­ TASK_RUNNING, но не помещена в runqueue в том, что пометить задачу и вставить в очередь - не одно и то же. Если заполучить блокировку runqueue_lock на чтение-запись и просмотреть runqueue, то можно увидеть , что все задачи в очереди имеют состояние TASK_RUNNING. Таким образом , утверждение "Все задачи в runqueue имеют состояние TASK_RUNNING" не означает истинность обратного жет быть помечена как утверждения . Аналогично, драйверы могут отмечать себя (или контекст процесса, под которым они запущены) как TASK_INTERRUPТIBLE (или TASK_UNINTERRUPТIBLE) и затем производить вызов торый удалит их из • процесс остается в runqueue (исключая runqueue) . schedule(), ко­ случай ожидания сигнала, тогда .. . . . . . -............ --. ---.. ---... -... -- ... -.. ---. -. -. --......... -... -.. -- -... -... . .
Я . 1ро l ,inux ..... _____ ............ n.inux • TASK_ INTERRUPTIBLE - задача в состоянии "сна", но может быть "раз­ бужена" по сигналу или по истечении таймера. • TASK_UNINTERRUPТIBLE - подобно TASK_ INTERRUPТIBLE, только задача не может быть "разбужена". • TASK_ZOMBIE - задача, завершившая работу, до того как родительский процесс ("естественный" или "приемный") произвел системный вызов wait(2) . • TASK_ STOPPED - задача остановлена, либо по управляющему сигналу, либо в резул_ьтате вызова • TASK EXCLUSIVE зуется только ptrace(2). не имеет самостоятельного значения и исполь­ совместно UNINTERRUPТIBLE (по с TASK_ INTERRUPТIBLE или с TASK_ OR). При наличии этого флага, будет "раз­ бужена" лишь эта задача, избегая тем самым порождения проблемы "гремящего стада" при "пробуждении" всех "спящих" задач. Флаги за­ дачи представляют не взаимоисключающую информацию о сост0янии процесса: unsigned long flags; /* /** флаги процесса , определены ниже* / Флаги процесса*/ #define PF ALIGNWARN OxOOOOOOO l /* Print alignment warning msgs * / /* Not implemented yet , only for 486* / #define PF_STARTING Ох00000002 / *создание* / #define PF_EXITING Ох00000004 / *завершение* / #define PF_FORKNOEXEC О х 00000040 / * создан , но не запущен* / #define PF_SUPERPRIV Ох00000100 / * использует привилегии суперп ользователя* / #define PF DUMPCORE Ох00000200 / * выполнен дамп памяти* / #define PF SIGNALED Ох00000400 / * " убит " по сигналу* / #define PF MEМALLOC ОхОООООВОО / * Распределение памяти* / #define PF VFORK Ох00001000 / * " Разбудить " родителя в mm_release */ #define PF USEDFPU Ох00100000 / * задача использует FPU this quantum (SМР) */ Переход процесса из одного состояние в другое показан на рис. 5.2. В коде ядра часто необходимо изменять состояние процесса. Предпочти­ тельнее всего для этой цели использовать функцию: set_task_state (task, state) ; / * Перевести задачу ' task ' в состояние ' state ' */ . . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - • - - - • - - - - • - - - • - - - - - - - - - - 1.. - - - - - - - - - • - - - - • - - - - - - - - _ , .
n.inux _. __ . __________ . _.. которая устанавливает указанное состояние для указанной задачи . По мере необходимости эта функция также предоставляет барьер памяти barrier), (memory чтобы гарантированно изменить состояние задачи на других про­ цессорах. В остальных случаях это эквивалентно выражению: ta sk - >state state ; ~ ~ sc/leduler Ф ~c hes tвsk to run: schedule( ) ~ !ls conte><t_sw!tch( ) ~ -"'"-''" Рис. 5.2. Состояния процесса Существует и другая функция, set_current_state(state), вызов которой эющ­ set_task_state(current, state). Данная функция и другие, связанные с описаны в файле <linux/sched.h>. валентен ней , 5.2.3. Дескриптор Структура task_struct процесса выделяется с помощью распределителя slab для обе­ спечения повторного использования объектов и "раскрашивания" кэша. В • .-. - ------ ------------ ----- - -- ------------. ----------------------. ~ --. -- -. --- ------ -•
Я , tlJII l , illll\ ...................... n.1nux ранних версиях ядра Linux (до версии 2.6) структура task_struct хранилась в конце стека ядра каждого процесса. Это позволяло архитектурам с неболь­ шим количеством регистров, таким как х86, вычислять местоположение дескриптора процесса с помощью указателя стека без использования допол­ нительного регистра для хранения местоположения. В современных версиях, когда дескриптор процесса динамически создает­ ся с помощью распределителя плит, была создана новая структура, thread_info. struct Данная структура снова находится в нижней части стека (для стеков, которые растут вниз) и наверху стека (для стеков, которые растут вверх). Новая структура также упрощает вычисление смещения его значе­ ний для использования в ассемблере. Procesa КerneJ Stack . . - - - - - - - - - - - . - hlgtlest memory address Start of Stac;k 1 - - - - - - - + - - - - - - f • .s tacl( polnter struct thread_struct current" t hread_info {} •- - - - - - - - - - - • lowest memory adl;Jre$& thread_i nfo hat а pointerlothe pl'II08$S descrlptor the proce11'$ struct task_struct Рис. Структура thread_info 5.3. Дескриптор процесса определена в struct thread inf o { и стек ядра <asm/thread_info.h> и имеет вид : • . . ..--............... -.......... --- ... -·. ----. . . ....... .. .. .. . ..... -. -· .. ........ ... .
n..1nux . ................. . struct task struct struct ехес domain unsigned long unsigned long u32 s32 mm_segment_t struct restart Ыосk unsigned long u8 *task; *exec_domain; flags; status; cpu; preempt count; addr_limit; restart_Ыock; prev ious_esp; supervisor_stack(OJ; }; Структура thread_info размещается в конце системного стека, выделенного для каждой задачи. В ней есть элемент структуру дескриптора задачи task, task_struct. который указывает на реальную Система идентифицирует процессы по значению уникального идентифика­ тора процесса (process identification, PID). Идентификатор число, представленное с помощью скрытого типа pid_t, PID - это целое который обычно соответствует целому типу со знаком int. Однако для обратной совмести­ мости со старыми версиями ОС Unix и Linux максимальное значение этого параметра по умолчанию ограничено значением 32768 (что соответствует типу данных short int). По желанию его можно увеличить до 4 млн. Для этого нужно отредактировать файл процесса сохраняется ядром в поле <linux/threads.h>. Идентификатор pid каждого дескриптора процесса. Это максимальное значение является важным, потому что оно определяет макси­ мальное количество процессов, которые одновременно могут существовать в системе . Хотя значения 32768 вполне достаточно для офисного компьютера, для больших серверов может потребоваться запустить значительно больше про­ цессов. Чем меньше это значение, тем скорее нумерация процессов будет на­ чинаться сначала, что приводит к нарушению полезного свойства: бОльший номер процесса соответствует процессу, который запустился позже. Если обратная совместимость со старыми приложениями не нужна, то админи­ стратор может увеличить максимальное значение идентификатора процес- •са прямо pid_max. во время работы системы, отредактировав файл /proc/sys/kemeV Как правило, в ядре для идентификации задачи используется прямая ссылка на соответствующую структуру • task_struct. По сути, в большей части кода .. . . .. .. ...... ··· · ··· ....... .. ........... .......................................... .
Ядро Linux .. .... .......... .. . .. . t\.iпux ядра, работающего с процессами, выпол няется обращение прямо к полям структуры task_struct. Нам нужно иметь возможность быстро находить дескриптор процесса, выполня ем ого в данный момент. Специально для это­ го создан макрос current. Конкретная реализация этого макроса зависит от используемой аппаратной платформы. В некоторых аппаратных платформах указатель на структуру task_struct, соответствующую выполняемому в на­ стоящий момент процессу, сохраняется в специальном регистре процессор а, что намного ускоряет доступ к ней. В ряде других архитектур, в частности х86 , с ограниченным набором регистров процессора общего назначения ис ­ пользуется тот факт, что структура th,-ead_info располагается в стеке . Это позволяет очень э ффективно вычислить ее адрес и , соответственно, опреде­ лить адрес структуры task_struct. Чтобы получить адрес структуры thread_info на платформе х86 и определить 13 бит указателя стека . Для этой це.riи предусмотрена функция current_thread_info(). Соответ­ значение параметра current, нужно замаскировать младшие ствующий код на языке ассемблера выглядит так: movl $ - 8192 , % еах andl %esp , % еах В этом фрагменте кода подразумевается , что размер стека составляет 8 8192 нужно использо ­ вать число 4096. Окончательно значение параметра current получается пу­ тем разыменования значен ия поля task полученной структуры thread_info: Кбайт. Если размер стека составляет 4 Кбайт, вместо current thread info( )- >task ; 5.3. Контекст процесса Одной из самых важных частей процесса является исполняемый программ ­ ный код, который считывается из исполняемого файла (executaЬle) и в ыпол ­ няется в адресном пространстве процесса . Обычно выполнение программы осуществляется в пространстве польз ователя. Когда в программе выполня­ ется вызов системной функ ции или воз никает исключител ьная ситуация , программа входит в пространство ядра. • . . ......... ........................................................................ ..
Глава n.inux .................. . 5. Как ядро у11рав. 1яс1 11ро11ссса,111 С этого момента говорят, что ядро "выполняется от имени процесса" и все это происходит в контексте процесса . В контексте процесса макрос current работает корректно . При выходе из режима ядра пр оцесс продолжает выпол­ нение в пространстве пользователя, если в это время не появляется готовый к выполнению бол е е при о р итетный процесс. В таком случае управление передается пл анировщ ику, который и выбирает для выполнения наиболее приоритетный проце сс. Системные функции и обр аботчики исключительных ситуаций имеют в ядре строго определенный интерфейс. Процесс м ожет начать выполнение в про­ странстве ядра 1ол ько п осредством одного из этих интерфейсов - любые обращения к ядру возм ожны только через эти интерфейсы . 5.4. Созд ание нового npouecca и его з аверш ение В литературе м ожно встретить самые разные о пределения термина "про­ цесс" , начиная от " экземпляр испол няемой пр ограммы " и з аканчивая "то, . что является р езул ьтатом работы системного вызова Linux, clone(2) или fork(2)" . В существует тр и типа процессов: 1. Фонов ые задачи ; 2. Потоки ядра; 3. Пользовательс ки е задачи . Потоки ядра порождаются с помощью функции лает системный вызов clone(2) kemel_thread(), в режиме ядра . Потоки ядра обычно не име­ ют пользовательско го адр есного пространства, т. е. му они явно выз ывают которая де ­ exit_mm(), p->mm = NULL, поэто­ daemonize(). например, через функцию Потоки ядра вс егда имеют прямой доступ к адр есн ому пространству ядра . Получают pid из нижнего диапазона. Р аботают в нул евом кольце защиты и, следовательно , имеют в ы сший приоритет во вс ех оп ерациях ввода/вывода и имеют преимущество п ер ед планировщи ко м зад ач . Пользовательские задачи создаются через системные вызовы fork(2)c • • И тот и другой обр ащаются к clone(2) или kemel/fork.c: do_fork(). • ... ................................................. ............................... .
\ Я 1 •ро l,i11ux ..... . ........ .... . . .. n.1nux Давайте рассмотрим , что же происходит, когда пользовательский процесс де­ лает системный вызов fork(2) . Хотя fork(2) и является аппаратно-зависимым из-за различий в организации стека и регистров , тем не менее, основную часть действий выполняет функция и размещена в do_ fork(), которая является переносимой kemel/fork.c. При ветвлени и процесса выполняются следующие действия: 1. Локальной переменной retval присваивается значение -ENOMEM, кото­ рое возвращается в случае невозможности распредел ить память под но­ вую структуру задачи. 2. Если установлен флаг CLONE_PID в параметре clone_.flags, тогда возвра­ щается код ошибки (-ЕРЕRМ). Наличие этого флага допускается, только если do_ fork() была вызвана из фонового потока (idle thread), т. е. из зада.­ pid == О (только в процессе загрузки). Таким образом , пользователь­ ские потоки не должн ы передавать флаг CLONE_PID в clone(2), ибо этот чи с номер все равно не "проскочит". · з. Инициализируется current->vfork_sem (позднее будет очищен потомком). Он используется функцией sys_ vfork() (системный вьrзов vfork(2), пере- • дает clone_ flags = CLONE _ VFORКICLONE _ VMISIGCHLD) для того, что­ бы "усыпить" родителя пока потомок не выполнит mm_release(), напри­ мер, в результате исполнения ехес() или exit(2). 4. В памяти размещается новая структура с помощью макроса struct(). alloc_task_ На х86 это прои~водится с приоритетом главная причина, по которой системный вызов GFP_ КERNEL . Это fork(2) может "заснуть". Если размести,ть структуру не удалось, то возвращается код ошибки -ENOMEM. 5. Все поля структуры текущего процесса копируются во вновь созданную структуру посредством присваивания *р = *current. Позднее , в поля, ко­ торые не наследуются потомком , будут записаны корректные значения. 6. Для сохранения реентерабел ьности кода, выполняется 7. Если "родитель" является пользовательским ресурсом , то проверяется - не превышен ли предел RLIMIТ_NPROC , если превышен -EAGAJN, если нет - у вели чивается uid p->user->count. вращается код ошибки цессов для заданного 8. blg kernel lock. - тогда воз­ счетчик про­ Если превышено системное ограничение на общее число задач threads, возвращается код ошибки -EAGAJN. - max_ • . .......................................... .... ....... ..............................
1 ·. 1ава n.inux __________________ _ 9. 5. Как я . 1ро ~ 11ран.1яе1 11ро11ессаш1 Если исполняемый формат программы принадлежит домену исполнения, поддерживаемому на уровне модуля, увеличивается счетчик ссылок соот­ ветствующего модуля. 10 . Если исполняемый формат программы принадлежит двоичному формату, поддерживаемому на уровне модуля, увеличивается счетчик ссылок соот­ ветствующего модуля. = О). 12.Потомок помечается как 'not-swappaЫe' (p-> swappaЫe = О). 11. Потомок помечается 13 . Потомок как переводится p->state = TASK 'has not execed' (p->did_ ехес в состояние т.е. UNINTERRUPТIBLE 14.Устанавливаются флаги потомка случае простого TASK_UNINTERRUPТIBLE, fork(2), 15 . Вызовом функции, это будет p->flags в соответствии с clone_flags; p->flags = PF _ FORКNOEXEC. kemel/fork.c:get_pid(), реализующей (p->pid) . в быстрый алго­ ритм поиска, находится pid потомка 16.Далее инициализируется остальная часть структуры task_struct потомка . pidhash и потомок ак­ тивируется. Обратите внимание на установку p->exit_signal в значение clone_flags & CSIGNAL, которое для fork(2) может быть только SIGCHLD, и на установку p->pdeath_signal в О. Сигнал pdeath_signal используется, В самом конце структура хешируется в таблицу когда процесс лишается "родителя" (в случае его "смерти") и может быть получен/установлен посредством команд системного вызова PR GET/SET_PDEATHSIG prctl(2) Задача создана. Для завершения задачи имеется несколько способов. • Выполнить системный вызов • Передать сигнал, приказывающий "умереть" ; • Вынужденная "смерть" в результате возникновения некоторых исклю­ exit(2); чений; • Вызвать bdflush(2) с func == 1 (эта особенность Linux оставлена для сохранения совместимости со старыми дистрибутивами, которые имели строку 'update' в /etc/inittab kupdate). на сегодняшний день эта работа выполняет­ ся процессом ядра • .. .-------------------------. - ----------------------------------------------------·, •
Я 1 tро 1-inux ......... •............. n..1nux Имена функций, реализующих системные вызовы, в с префикса sys _, Linux начинаются но они , как правило, ограничиваются только проверкой аргументов или платформа-зависимой передачей информации, а фактиче­ ски всю работу выполняют функции do_. Это касается и которая sys_exit(), вызываетdо_ехit() для выполнения необходимых действий. Хотя, в других частях ядра иногда встречается вызов do_exit() из sys_exit (), на самом деле вызьшается kemel/exit.c. Обычно уничтожение процесса инициируется самим процессом. Это проис­ ходит, когда. в самом процессе вызывается системная функция exit(). Причем это может произойти как явно , когда вся работа программы сделана и нужно завершить ее работу, так и неявно , при выполнении возврата из основной процедуры любой программы с именем main(). Другими словами , компилятор языка с помещает вызов функции exit() в код, который выполняется посл е воз врата из процедуры main(). Процесс также может быть заверш ен непреднамеренно . Так происходит, когда процесс по­ лучает сигнал и л и во з никает исключительная ситуация , которую тот не мо­ жет обработать ил и проигнорировать. Независимо от того, каким образом завершается процесс , основную массу работы выполняет функция определенная в фа йл е do_ exit(), kemel/exit.c. После окончания р аботы функции do_exit() дескриптор завершившегося процесса все е щ е существует в системе , но сам процесс находится в состоя - 1-1ии ЗОJ116и и не может выпол няться . Как уже говорилось выше, это позволяет системе получить информацию о дочернем процессе после его завершения. Следовательно , освобождение ресурсов после завершения процесса и уда­ ление его дескриптора должны происходить в разные моменты времени .. После того как род ител ьский процесс получил информацию о завершенном дочернем проце ссе , л ибо уведомил ядро, что эта информация ему больше не нужна, структур а task_struct дочернего Семейство функций wait() реализовано через единственную (и достаточно сложную) системную функцию ствие - процесса освобождается. wait4(). Она выполняет стандартное дей­ приостанавливает выполнение вызывающей задачи до завершения одного из ее дочерних процессов. При этом функция возвращает идентифи­ катор PID завершенного дочернего процесса. При вызове функции wait4() передается указатель на область памяти, которая после возврата из функции будет содержать код завершения дочернего процесса. Когда приходит время окончательно освободить дескриптор процесса, 13ызы­ вается функция release_task(), которая выполняет указанные ниже операции: • . . .. . . .. . .. . . . . .. . . ... .. -- ............................................... . ....... .. . .
Г.11ава n..inux ___ ____ _____ . __ ___ _ • 5. Как ядро yr,paBJIЯCI Щ)ОЦССС,1\111 Вызывается функция_exit_ signal(), в которой затем вызывается функция _ unhash_process(). Из последней функции вызывается еще одна функция - detach_pid(), - которая удаляет процесс из хеш-таблицы идентифика­ торов пр о цессов pidhash и сам процесс из списка задач. • В функции _exit_signal() освобождаются абсолютно все ресур с ы , кото­ рые продолжают использоваться в завершившемся процессе, а также под­ биваются статистические данные использования системных- р е сурсов . • Если завер шившаяся задача была последним членом группы потоков , а ее лидер находится в состоянии зомби, то функция release_task() уведомляет род ительский·процесс лидера группы, находящегося в состоянии з омби. • Из функц ии release_task() вызывается функция put_task_struct(), в которой освобождаются страницы памяти, содержащие системный стек процесса и структуру держащая 5.5. thread_info, а также структуру task_struct. освобождается блочная кеш- п амять , со­ Потоки Благодаря потокам (threads) появляется возможность выполнения несколь­ ких потоков команд в общем адресном пространстве памяти. Потоки также могут совместно использовать открытые файлы и другие ресурс ы . Потоки позволяют р еализовать режим ( concuпent programming) одновремен ного выполнения пр ограмм и обеспечить истинный параллелизм на мн огопро­ цессорны х системах. Реализ ация п отоков в операционной системе ния ядра Linux Linux уникальна. С точки зре­ не существует отдельной концепции потоков. В ядре Linux все потоки реализованы в виде стандартных процессов. В нем нет никакой особенной семантики для планирования выполнения потоков или каких-ли­ бо особенных структур данных для представления потоков. Поток - это просто процесс, который использует некотор ы е ресурсы со вместно с другими процессами . Каждый поток имеет свою структуру task_struct и с точки зрения ядра явля­ ется обычным пр оцессом, который (так уж случилось!) совме стно исполь­ зует с другими процессами общие ресурсы, такие как адресно е простран­ ство • . .. . . . --- -... --- ... --. -- . ·-- --- -- ---- ---. -.. --. -··- --·- --- -- .. -- ---· ....... ·- ----... ..
Я : 1ро Linux ______________________ n..inux В других операционных система, таких как Windows, все немного иначе. В них существуют средства дл я явной поддержки потоков в ядре, ко­ торые называют lightweight process (процессы с быстрым переключением - процесс с быстрым переключением контек­ ста - свидетельствует о разнице в философии, принятой в Linux и других операционных системах. В этих системах потоки - это абстракция, которая контекста). Само название обеспечивает облегченные и более быстрые с точки зрения выполнения бло­ ки кода, по сравнению с обычными тяжеловесными процессами. Для опера­ ционной системы Linux потоки это просто способ совместного использо­ - вания ресурсов несколькими процессами, которые и так имеют достаточно малое время переключения контекста. Для создания потоков используется та же функция clone(), но ей передаются флаги, указывающие на то, какие ресурсы должны использоваться совместно,: clone(CLONE_VM CLONE FS CLONE FILES CLONE SIGHAND , О) ; Резул ьтат выполнения этого кода будет таким же , как и при выполнении обычной функции fork(), за исключением того, что адресное пространство, ресурсы файловой системы, дескрипторы файлов и обработчики сигналов останутся общими . Другими словами, и новая задача, и родительский про­ цесс являются тем , что в народе популярно называется потоками. Для сравнения вы зов обычный функции cl o ne(SIGCHLD , Функцию vfork() fork() может быть реализован так: О) ; можно реализовать следующим образом: clone(CLONE_ VFORK CLONE VM I SIGCH LD , Флаги, которые передаются системной функции О ); clone(), указывают особен­ ности поведения нового процесса и конкретизируют, какие именно ресурсы должны быть общими для родительского и дочернего процессов, Далее при­ ведены флаги системной функции h>, и вызываемый ими эффект: clone(), описанные в файле <linux/sched.
Глава n.inux ______ ____ ________ _ • CLONE_FILES - Как ядро управляет процессами родительский и дочерний процессы совместно исполь- зуют открытые файлы. • CLONE FS - 5. • информация о файловой системе будет использоваться совместно. • CLONE_IDLETASK - установить значение PID в О. создает новое пространства имен для дочерней за­ • CLONE_ NEWSNS дачи. • CLONE_PARENТ - родительский процесс для вызывающего процесса становит~я родительским для дочернего. • CLONE_ SETТID - возвращает значение идентификатора TID в простран­ ство пользователя. • CLONE_ SETTLS - для дочернего процесса создать новую область ло­ кальных данных потока. • CLONE_SIGHAND - у родительского и дочернего процессов будут об­ щие обработчики сигналов и сигналы блокирования. • CLONE_SYSVSEM SEM UNDO. • CLONE_THREAD - общей будут семантика обработки флага родительский и дочерний процессы будут принад­ лежать одной группе потоков. • CLONE_VFORК - родительский процесс будет находиться в заморожен­ ном состоянии, пока дочерний процесс не возобновит его работу. • CLONE_ UNTRACED - запретить трассирующему процессу ние флага CLONE_PTRACE для дочернего процесса . • CLONE_ STOP STOPPED. использова­ запустить процесс и перевести в состояние • CLONE_CHILD_ CLEARTID - TASK очистить идентификатор ТID для дочер­ него процесса. • CLONE_CHILD_SETTID - установить идентификатор TID для дочерне­ го процесса. • CLONE_PARENТ_SETЦD - установить идентификатор TID для роди­ тельского процесса. • CLONE_ VМ - у родительского и дочернего процессов будет общее адрес­ ное пространство . , _------- ----------- -.. --. -. ---. ---. -------. --.. --. ------------- . -- - .. --- ----. --- -
...................... t'1.1пux }l ,1po J,i1111, Часто требуется выполнить в ядре некоторые операции в фоновом режиме, В ядре такая во зможность реализована в виде потоков ядра (kernel thread) - обычных процессов, которые выполняются исключительн о в пространстве ядра . Существенным отличием между потоками ядра и обычными процес­ сами является то, что потоки в ядре не имеют своего адрес ного пространства (значение указателя тт для них равно NULL). Эти потоки работают 'fолько в пространстве ядра, и их контекст не переключается в пространство поль­ зователя. Тем не менее , потоки ядра планируются и вытесняются так же, как и обычные проце ссы. Потоки ядра в Linux выполняют определенные задачи. Самые важные из - .flush и ksoftirqd. Чтобы увидеть список таких потоков в вашей систе­ Linux, воспользуйтесь командой ps -ef Их довольно много! Потоки ядра них ме создаются во время начальной загрузки системы другими такими же потока­ ми. Это и понятно , поскольку поток ядра может быть создан только другим потоком ядра . В ядре эти потоки обрабатываются автоматиче ски : все новые потоки ядра разветвляются от специального процесса kthreadd, запущенного в ядре . Интерфейс для порождения нового потока ядра из существующего описан в файле <linux/kthread.h> и приведен ниже. stru ct task_s truct *kthread_create (int (*threadfn) (vo i d *data) , void *dat a , const c h a r na mefmt[] Новая задача создается процессом kthread, запущенн ым в ядре , с помощью clone(). В новом процессе будет выполнять­ ся функция threadfn(), которой передается аргумент data. Процессу будет присвоено имя , указанное в переменной namefmt, а в списке аргументов вызова системной функции переменной длины указываются параметры форматировани я в стиле функ­ ции printf() языка С. После создания процесс находится в н езапущ енном состоянии (unrunnaЫe образом вызвать функц ию state). Для его запуска нужно явны м wake_up_process(). Чтобы создать процесс и сразу же отправить его н а выполнен ие , можно воспользоваться еди нственной функ­ цией kthread_run :
111ава r.linux __________________ _ 5. Как sщро у11равш1с 1 11ронссса~111 st r uct t ask_str uct *kthread_ run (int ( *threadfn) (void *data ) , void *data , const char namefmt[] , ... ) Описанная выше процедура запуска процесса в ядр е реализована в виде макроса, в котором вызываются обе функции , process(), kthread_ create() и wake _up _ как показано ниже. После запуска поток ядра продолжает выполняться до тех пор , пока в нем не будет вызвана функция do_exit(), либо пока в какой-либо другой части kthread_stop() . В качестве параметра этой структуры типа task_struct, возвраще нной ранее ядра не будет вызвана функция функции передается адрес функцией kthread_ create(): int kthread_st op (stru ct task struct *k) 5.6. Планировщик Работа планировщика заключается в разделении CPU между нескол ькими процессами. Реализация планировщика размещена в файле Соответствующий заголовочный файл (прямо kemel/sche,d.c. include/li nux/sched.h подключается или косвенно) фактически к каждому файлу с исходным текстом . ядра. Поля task_struct, которые • p->need_resched - используются планировщиком: это поле устанавливается если schedule() должна быть вызвана при 'первом удобном случае' . • p->counter - число тактов системных часов , оставши хся · д о окончания выделенного кванта времени , уменьшается по таймеру. Когда значение этого поля становится меньше либо равно нулю , то в н его записы вается ноль и взводится флаг p->need_resched. Иногда это поле называют "дина­ мическим приоритетом" ('dynamic priority') процесса потому как он мо­ жет меняться . • ... . . . . --- -- -.... -- ---- ...................... -- ... -- ............................. --
Я . tро (,i1111x • p->priority - ______________________ rt.inux статический приоритет процесса, может изменяться только через системные вызовы , такие как или • p->rt_yriority- приоритет реального • nice(2), POSIX.1 Ь sched_ setparam(2) 4.4BSD/SVR4 setpriority(2). времени (realtime priority). р->policy- политика планирования, определяет класс планирования зада­ чи. Класс планирования может быть изменен системным вызовом sched_ setscheduler(2). Допустимые значения: SCHED_ OTHER (традиционные процессы UNIX), SCHED_FIFO (процессы реального времени POSIX.1Ь FIFO) и SCHED_RR (процессы реального времени POSIX round-roЬin). Допускается комбинирование любого из этих значений с SCHED_ YIELD по ИЛИ (OR) чтобы показать, что процесс решил уступить CPU, напри­ мер, при вызове sched_yield(2). Процесс реального времени FIFO будет работать до тех пор, пока не: а) запросит выполне1:1ие блоковой опера­ ции ввода/вывода , Ь) явно не отдаст CPU или с) будет вытеснен другим процессом реального времени с более высоким приоритетом в p->rt_priority). SCHED_RR то (значение же самое, что и SCНED_FIFO, за исклю­ чением того, что по истечении выделенного кванта времени, процесс по­ мещается в конец очереди runqueue. Алгоритм планировщика достаточно прост, несмотря на очевидную слож­ ность функции schedule(). Сложность функции объясняется реализацией трех алгоритмов планирования, а так же из-за учета особенностей SMP (мультипроцессорной обработки). 5. 7. Управление процессами из консоли 5.7.1. :Командырs, nice и kill Получение информации о процессе Современные операционные системы устроены так, что каждому процессу присваивается уникальный номер - PID (Process ID, ИД процесса), исполь­ зуя который можно управлять процессом, например, можно завершить про­ цесс или изменить его приоритет. • 88- ------. --------------------------------------------------------------------------.
n.lпux ...... __ ......... __ Узнать PID 1 :11а11а 5. 1{,щ sщро у11раш1щ•1 IIJ)OЦ('CC:IMII можно с помощью команды ps. Команда ps , введенная без па­ раметров, просто показывает список процессов, запущенных на текущем терминале. Видно, что сейчас запущен bash и сама команда ps (правда, на момент завершения вывода процесс с ID 975 уже не будет существовать , но на момент самого вывода такой процесс существовал), см. рис. Рис. 5.4. Комаида 5.4. ps Параметр -а позволяет вывести список всех процессов пользователя. Посмотрите на рис. соли t t у1 - 5.5 на консоли ttyЗ запущена программа nano, на кон­ программа р s. Рис. 5.5. Команда ps -а Если нужно вывести процессы какого-то определенного пользователя, тогда используйте параметр -и: $ p s - u r oo t • .. . . . ----.. -................................... -... -.................. -............ .
Я J •ро - - -- ---· · · -·· · ·-·-···-t\.iпux l.inux Вывести абсолютно все процессы можно с помощью опции -А . Обратите внимание на регистр опции! Поскольку в системе проце ссов будет- очень много , лучше перенаправить вывод программы на команду less для более удобного про смотра (рис. $ ps -А 5.6): I less Ри с. 5. ба. Команда Ри с. 5.66. Ко;ианда ps ps -А -А I I l ess less (начало вывода) (завершение вывода) • - - ------------------------------····-·· ··········-···--··---··--· ·--··---··--··--·-·
Гла ва n..inux .................. . 5. Как ядро управш1ет процессами Примечание. Для выхода из программы less нажмите q на кла­ виатуре. Листать вывод можно стрелками вверх и вниз. Команда ps сортирует процессы по PID. Колонка ТТУ - это терминал, к кото­ рому привязан процесс . Если в этой колонке вы видите знак ?, значит, про­ цесс не привязан ни к одному из терминалов. Как правило , это системные процессы-службы. Они запускаются без привязки к терминалу. Чтобы отобразить только процессы без привязки к терминалу, используется опция -х (рис. 5.7). Рис. Колонка STAT - 5. 7. Команда ps -х I less это состояние , в котором находится процесс. Возможные з начения для этой колонки приведены в таблице 5.1. Обратите внимание: колонка STAT есть только , когда программа з апущена с параметром -х. Если программа запущена с другими параметрами, например , -А, вместо нее будет колонка TIME, которая сообщает занимаемое процессом процессорное время. • • •····· · ···························································--··············8 8
...................... а1пuх И , tро l , i1111\ Таблица 5.1. Возможные состояния процесса Описание Состояние Процесс в непрерывном сне (как правило, ожидает вво- D да/вывода) Выполняется в данный момент R 20 секунд, поR или в состоя- Ожидание (то есть процесс "спит" менее s еле чего он переходит или в состояние ние т D) Процесс остановле~ То же, что и Т, но причина остановки t - останов отлад- чиком w Процесс в свопинге (подкачке) х Процесс мертв, вы его никогда не увидите z его родителем, то есть процесс-родитель еще не считал Процесс-зомби - он уже завершен, но не "похоронен" код завершения У команды ps есть несколько синтаксисов установки параметров. Мы ис­ пользовали ВSD-синтаксис . Например, для вывода всех процессов в стан­ дартном синтаксисе используется команда -е, а в нашем случае - -А. Вы вольны использовать любой синтаксис, но в случае с ВSD-синтаксисом про­ грамма ps выводит дополнительное состояние процесса (работает подобно ps в системе BSD). Дополнительное состояние процесса описа­ программе но в таблице Таблица 5.2. 5.2. Дополнительное состояние процесса (ВSD-синтаксис) Состояние Описание < Высокий приоритет • . .. ............................................................... . ........ . ... . . .. .
n.1nux .................. . N Низкий приоритет L У процесса есть страницы, заблокированные в памяти s Это лидер сессии / Процесс является многопотоковым + Находится на первом плане в группе процессов Последняя колонка вывода ps - это смо. Она содержит команду, которой был запущен процесс. Не просто название исполнимого файла, но путь (если он был указан в команде) и переданные программе параметры . Если программа была запущена без указания полного пути к исполнимому файлу, и вы хотите знать, где он находится, введите команду whi c h, напри­ мер: $ which nan o / Ьin / nano Если вам нужно узнать PID определенного процесса, но вам не хочется про­ сматривать длинный список системных процессов, используйте команду grep, как фильтр. Например, следующая команда позволит нам узнать PID процесса # ps -А sshd (это SSH-cepвep): I grep sshd Если такой процесс не запущен, вывод будет пуст. Или же вы получите вы­ вод вроде этого: 929 ? 0 0: 0 0:0 0 ss hd Изменение приоритета процесса Когда мы знаем PID процесса, мы можем изменить его приоритет. В неко­ торых случаях полезно изменить приоритет процесса. Например, можно • ·········--··········--···---·-·-···-··-····-·-·---······---·---···-··--···--·····-8i8
Я .· tро l,iш1x ...................... n.iпux повысить приоритет процесса, выполняющего резервное копирование, что­ бы программа успела за ночь создать все необходимые резервные копии и чтобы этот процесс утром уже не мешал нормальной работе сервера . Запустить программу с определенным приоритетом можно командой nice : # nice - n <приори т ет> команда Здесь приоритет задается от -20 аргументы (максимальный приоритет) до 19 (мини­ мальный). Есл.и процесс уже был запущен, и вы не можете его прерывать, но повысить приоритет нужно, используйте команду # renice -n <приоритет> -р renice: , PID Аварийное завершение процесса Если процесс завис и его нельзj_! завершить, как обычно, тогда для его ава­ рийного завершения используется команда kill. Формат вызова этой ко­ манды следующий: $ kill [опции] PID Конечно, перед этим нужно узнать команда kill PID процесса PID процесса . На рис. 5.8 изображена в действии: сначала я вывел список процессов , чтобы узнать nano (1035), затем я ввел команду kill 10 35 , чтобы "убить" этот процесс. Наконец, я вывел список процессов еще раз , чтобы убедиться, что процесс папа завершен. Используя параметры программы , можно по-разному завершить процесс .. Самый эффективный сигнал 9 (КJLL) - означ<1ет аварийное завершение про­ цесса. Программа не может игнорировать или как-либо обработать этот про­ цесс. Если нужно попытаться корректно завер шить работу программы, ей отправ­ ляют сигнал 15 (ТЕRМ), означающий , что программа должна освободить все занятые ресурсы, сохранить все данные. Вот только если программа за- • . .. .. . . . .. .. . . . . ... .. .. ... .. .... .. . ... . .. . .. . .. . ... . . . .. . . .. ...... .. . ....... .. . .. . . .
Глава n.i~ux __________________ _ 5. Как ядро у11раш1яс1 11роцссса\11t висла и не отвечает на запросы пользователя , этот сигнал мало чем поможет, но попытаться стоит. [ rootl• 1ш:,, Р ID ТГУ llшs t 1из~• Ш1 :fШ :ИН 1 t., 1:i 11?.'} t t,Jt 1 root l• 1ос,, l lн,:: t Hli 111 \..111 1 гооt f• l11c,1 11111. 1 111 Рис. Сигнал 1 9 • 111 1'" TIME (STOP) НН:НН 5.8. ,1 СМJ) н,1но р; Н!У, Использование команды kill позволяет временно приостановить работу программы, а сигнал 18 (CONT) - возобновить приостановленный ранее процесс. Для сетевых служб полезен сигнал 1 (НUР), означающий, что процесс дол­ жен перезапуститься и перечитать файл конфигурации. Полезно, когда вы изменили файл конфигурации и хотите, чтобы демон был перезапущен (хотя для этого правильнее использовать команду при получении сигнала se r v i ce). Обычная программа 1 завершает работу. Пример отправки сигнала: $ k i ll - 9 1035 Если вам лень получать пользуя команду PID killa l l , процесса, можно завершить его и по имени, ис­ например: $ killall nano • ·-------···--··--·-·-···--·---··--····--------··--·-·-·-·······--·-··········--··- - 8 8
И .' tро l,i1шx ......... . ............ t'l.1nux Вот только если в вашей системе есть два процесса с именем папо, например, один на консоли tty2, а другой на - tty4, то будут завершены оба процес­ са. Если это то, что вам нужно , используйте лучше использовать команду kil l killall, в противном случае для завершения именно того процесса, который можно завершить . Еще есть команда xkill, позволяющая "убить" программу, имеющую гра­ фический интерфейс. Такие программы можно завершить и командой но программа xkill kill, предоставляет графический метод завершения . После ввода этой команды указатель мыши примет вид черепа . Для завершения программы нужно щелкнуть по ее окну. 5. 7.2. Команда top Как было отмечено ранее, программа ps по умолчанию сортирует процессы по колонке PID, а не по колонке TIME. Конечно , можно использовать раз­ личные параметры программы, чтобы добиться нужного нам вывода, но все равно программа не будет показывать ситуацию в реальном времени. Если же вам нужно знать, что происходит с вашими процессами в реальном вре­ мени, вам нужно использовать программу .. Рис. 5.9. top Команда (рис. top 5.9). • . . .. . . . . . . . ------------------------.. ---. -- -... -.. -- -... ---. -. ---.... -... -...... -.
t\.1пux .................. . 1 1ава :-. Kai..: il. tJIO ~••рав. 1щ•1 11po11rcc:l\111 Назначение колонок программы описано в таблице Таблица 5.3. Колонки программы top Описание Колонка PID PID USER грамму) Приоритет процесса Значение NI RES процесса Владелец процесса (пользователь, запустивший про- PR VIRT 5.3. nice Виртуальная память, которая используется процессом Размер процесса, который не перемещается в область подкачки SHR Разделяемая память, используемая процессом s Состояние процесса ¾CPU Процессорное время , занимаемое процессом в данный момент ¾МЕМ ТIМЕ+ Память, используемая процессом Процессорное время , которое было потрачено с момента запуска процесса Команда запуска процесса COMMAND При просмотре списка программы top вы можете управлять сортировкой процессов с помощью нажатия клавиши торой сортируется список процессов выполняется по колонке • F, которая изменяет колонку, по ко­ (рис . 5.10). По умолчанию сортировка %CPU . .--------. -----. -----------. --- --- ------------- --·----------- --------.---. --.. ---.-tllll
Я J tl)CI l ,illll\ Рис. .:.................... n.inux 5.10. Выбор колонки, по которой осуществляется сортировка Нажатие клавиши <U> показывает только процессы определенного пользо­ <U> нужно будет ввести имя пользователя , процессы вы хотите просмотреть , или нажать Enter, чтобы просмотреть про­ вателя. После нажатия которого цессы всех пользователей. 5.7.3. Информация об использовании памяти и дискового пространства Хотя управление памятью и ди·сковым пространством не совсем относит­ ся к управлению процессами, но эти самые процессы активно "поедают", как память, так и дисковое пространство, поэтому иногда полезно знать, как просмотреть информацию об использовании памяти (команда кового пространства (команда df ), см. рис. free ) и дис­ 5.11. • ID- -.---.. --.. ---.. --.. ---.. -... ----.--.. --... --.. --... -.. ---.. --.. --... --.. ---.. -...
1J1a11a 5. t'l.1nux .................. . Рис. 5.11. Кол,анды К:11, sщро )'lll)ШIJ ISI{' 1 IIJ)OЦ~t· t·:1м11 free и df -Н Программа fr e e выводит информацию об использовании памяти (Mem) и подкачки (swap). Колонка total - это общее количество памяти в килобай­ used - использованное количество памяти (тоже в килобайтах), f r ee свободно памяти , shared - разделяемая память , buff/ cache - размер кэша, availaЫe - общий объем доступной памяти. тах, Параметр -Н команды df означает вывод информации об объеме в удобных для восприятия человеком единицах , то есть в мегабайтах и гигабайтах. Обратите внимание на значение buff/ cache в выводе команды f r ee . Оно показывает сколько памяти задействовано под буфер ввода/вывода и кэш. В нашем случае (рис. 5.11) - примерно 323 Мб. На реальном сервере это зна­ чение будет гораздо выше. Немного освободить память можно , очистив кэш. Для этого введите команду: sync ; echo 3 > /proc/sys/vm/drop caches Сначала мы командой sync сбрасываем содержимое буферов на диск, а за­ тем уничтожаем кэш . Если просмотреть затем информацию об использова­ нии памяти , то вы увидите , что размер кэша был уменьшен почти в три раза (рис. • 5.12). Однако помните , что эта команда может негативно отразиться .----.---. ---. -----------------------.-. ---.-----. -. ------------. -----------------tll!I
Я , tро [,i1шх ...... ________________ n..inux на стабильности системы и на скорости ее работы. Не всегда очистка кэша таким вот варварским образом Рис. 5.12. До это хорошо . - sync; echo 3 > /proc/sys/vm/ drop_ caches и после ввода комаиды 5. 7.4. Команда Команда f user fus e r позволяет узнать, какой процесс открыл тот или иной ресурс, например , файл или сетевой порт. Примеры использования программы: f user - va 23/tcp fu ser - va /chroot/etc/resolv.conf В первом случае мы получим идентификатор процесса, открывшего ТСР­ порт 23, во resolv.conf. втором - идентификатор процесса, открывшего файл Что делать далее процесс командой - /chroot/etc/ решать вам , например, можно "убить" этот kill . • I D--.--------------.. ---.-.----- -.----------.-.----.------------.------.-----.-----.
n.inux ___ ____ ____ : ______ _ Глава 5. Как ядро у11равляет 11роцессам11 В этой важной главе мы разобрались , как ядро управляет процессами из ­ нутр и и как управлять процессами из командной оболочки . • .------------.--.- ----. ---.. ---.------.. -------.-.--. --------. ------------... -.. ----1118
Глава 6. Обработка прерываний
Я , 1ро l,inux ...................... n..inux 6.1. Что т акое прерывания Прерывания позволяют аппаратным устройствам взаимодействовать с про­ цессором. Например, при наборе на клавиатуре контроллер клавиатуры (или другое устройство, которое обслуживает клавиатуру) генерирует прерыва­ ние , чтобы объявить операционной _системе о том, что произошли нажатия клавиш. Прерывания - это специальные электрические сигналы, которые аппаратные устройства посылают процессору. Процессор получает преры­ вание и дает сигнал операционной системе о том, что ОС может обработать новые данные. Аппаратные устройства генерируют прерывания асинхр,он­ но по отношению к тактовому генератору процессора - прерывания могут возникать непредсказуемо , в любой момент времени. Следовательно, работа ядра может быть прервана в любой момент для того, чтобы обработать пре­ рывания . Физически прерывания производятся электрическими сигналами, которые создаются устройствами и направляются на входные контакты микросхемы контроллера прерываний. Контроллер прерываний в свою очередь отправ­ ляет сигнал процессору. Процессор выполняет детектирование сигнала и • прерывает выполнение работы для того, чтобы обработать прерывание. al-·--·--------·----·----------------·---··--------·-----------··-··--·············· · •
t'liпux 1J iaвa __________ ... ____ _ (1. Обрабо~ 1,а 11pt·p1.111:11111ii После этого процессор извещает операционную систему о том, что произо­ шло прерывание и операционная система может соответствующим образом это прерывание обработать. Различ ные устройства связаны со своими прерываниями с помощью уни­ кальных числовых значений, соответствующих каждому прерыванию. От­ сюда следует, что прерывания, поступившие от клавиатуры, отличаются от прерываний , поступивших от жесткого диска. Это позволяет операционной системе различать прерывания и иметь информацию о том, какое аппаратное устройство произвело данное прерывание . Поэтому операционная система может обслуживать каждое прерывание с помощью своего уникального об­ работчика. Идентификатор ы , соответствующие прерываниям, часто называются лини­ ями запросов на прерывание (inteпupt request lines, IRQ lines) . Обычно это IRQ, равное О, IRQ, равное 1, - прерывание клавиатуры. Одна­ некоторые числа. Например , для платформы РС значение это прерывание таймера, а ко не все номера прерываний жестко определены. Прерывания, связанные с устройствами шины PCI, например, назначаются динамически. Друг.пе платформы, которые не поддерживают стандарт PCI, имеют анал огичные функции динамического назначения номеров прерываний. Основная идея состоит в том, что определенные прерывания связаны с определенными устройствами, и у ядра есть вся эта информация. Аппаратное обеспечение, •чтобы привлечь внимание ядра, генерирует прерывание вроде "Была нажата клавиша! Ее нужно обработать". 6.2. Обработчики прерывания 6.2.1. Что такое обработчик прерывания? Обработчиком прерывания (interrupt handler) называется функция, кото­ рую вызывает ядро в ответ на поступление определенного прерывания. Каждому устройству, которое может генерировать прерывания, в ядре соот­ ветствует свой обработчик прерывания. Например, одна функция обрабаты­ вает прерывание от системного таймера , а другая - прерывания, сгенериро ­ ванные клавиатурой . Обработчик прерывания для определенного устройства • .--... -----.---.----.. --....... --.. ---.-------.. ----.--.------------.----.--------ID
Ящю l,inux . _-_ ................... rL.inux является частью драйвера этого устройства - кода ядра, который управляет устройство~. В Linux обработчиком прерывания является обычная функция, написанная на языке С - ничего фантастического в обработчике прерывания нет. Все функции-обработчики должны соответствовать определенному прототипу, чтобы ядро могло стандартным образом передавать информацию обработ­ чику, а во всем остальном - это обычные функции. Обработчики прерываний вызываются в специальном контексте , который называется коюпекстом прерывания (interrupt context). В этом контексте код не может быть блокирован. Прерывание может возникнуть в любой момент времени, поэтому обработ­ чик прерывания может быть вызван когда угодно. Крайне важно, чтобы об­ работчик прерывания выполнялся очень быстро и возобновлял управление прерванного кода как можно скорее. Поэтому, хотя для аппаратного обеспе­ чения и важно , чтобы прерывание обслуживалось немедленно , для осталь­ ной системы важно, чтобы обработчик прерывания выполнялся в течение максимально короткого промежутка времени. Обработчик прерывания , как минимум, должен отправить подтверждение устройству, что прерывание получено. Конечно, в реальной жизни обработ­ чик прерывания выполняет гораздо более сложную работу. Например, об­ работчик прерывания сетевой карты должен скопировать пакеты из памяти сетевого адаптера в память компьютера и обработать их. Как видите, это гораздо больше, чем просто отправить подтверждение, что прерывание по­ лучено . 6.2.2. Регистрация обработчика прерывания Как уже было отмечено , обработчик прерывания является частью драйвера устройства, который управляет аппаратным устройством . С каждым устрой­ ством связан свой драйвер и есл'и устройство использует прерывания (в большинстве случаев это так), драйвер должен зарегистрировать обработ­ чик прерывания. Регистрация обработчика осуществляется с помощью функции определенной в request_irq(), linux/interrupt.h: 1111-....................................................................... ~ ........ '
1а lа ва n..inux _________________ _ / * r e qu e st_irq : за н имает ука з а нн ую int requ e st_ irq (unsigned int i rq, irq_handler_ t handler , unsigned l6ng flags , const char *name , void *dev ) Первый параметр - линию (1 . Ofipafio I К.1 llf)t• p1,1щ11111i1 IRQ * / это номер прерывания. Для некоторых устройств вроде клавиатуры, таймера, номер прерывания жестко закреплен. Для большин­ ства других устройств это значение определяется динамическим путем. Второй параметр - указатель на функцию обработчика прерывания. Эта функция вызывается операционной системой в момент получения сигнала прерывания. Следует обратить внимание на специфический прототип функ­ ции-обработчика. typedef irqreturn t (*irq_handler t ) (in t , vo id * ); Обратите внимание на специфический прототип этой функции . Ей переда­ ются два параметра , а она возвращает значение типа irqreturn_t. Эту функ­ цию мы рассмотрим чуть позже . Третий параметр , .fiags, может быть равен О или содержать битовую маску 1 флагов , представленных в заголовочном файле linux/interrupt.h. Рассмотрим некоторые из флагов: • IRQF _DISABLED - если данный флаг установлен, то во время выпол­ нения обработчика прерываний все прерывания будут запрещены. Если флаг не установлен , то при выполнении обработчика прерываний все другие прерывания, кроме собственного, разрешены. В большинстве об­ работчиков прерываний данный флаг не устанавливается, поскольку запрещать все прерывания - это плохая идея. Да'нный флаг используется для критичных по времени обработчиков прерываний , которые должны выполняться очень быстро. • . IRQF _ SAMPLE_ RANDOM - • этот флаг указывает, что прерывания, сгене­ рированные данным устройством, должны вносить вклад в пул энтропии . ядра . Последний обе спечивает генерацию истинно случайных чисел на основе различных случайных событий. Если этот флаг указан, то момен­ ты времени , когда приходят прерывания , занос ятся в пул в виде энтропии. .-----.. --- ------.. --· ·-· -............ -· .......... ·-.. ·-...................... -·· ·-1111 '
Н , 11111 l ,illll\ _.............. _...... n.1nux Этот флаг нельзя устанавливать, если устройство генерирует прерывания в предсказуемые моменты времени (как, например , системный таймер) или на устройство может повлиять внешний злоумышленник (как, напри­ мер, сетевое устройство). • IRQF _ ТIMER - этот флаг указывает, что данный обработчик прерывания обслуживает системный таймер. этот флаг указывает, что данный номер • IRQF _SHARED - IRQ может совместно использоваться несколькими обработчиками прерываний. Его нужно использовать при регистрации обработчика прерываний, если по­ следний использует одну и ту же линию IRQ с другими обработчиками прерываний . Если флаг сброшен, то для одной линии IRQ может суще­ ствовать только один обработчик прерывания. Четвертый параметр (name) содержит АSСП-строку, описывающую устрой­ ство , связанное с данным обработчиком прерывания . Например, для обра­ ботчика прерывания клавиатуры персонального компьютера данный пара­ метр содержит строку "keyboard". Текстовые имена устройств используются для взаимодействия с пользователями с помощью интерфейсов /proc/irq и / proc/interrupts. Пятый параметр (dev) вающих общие линии используется в обработчиках прерываний, обслужи­ IRQ. При освобождении обработчика (этот процесс будет рассмотрен ниже) в параметре dev указывается уникальный иденти­ фикатор, который позволяет удалить только требуемый обработчик из задан­ ной линии IRQ. Без этого параметра ядро не смогло бы определить, какой именно обработчик прерывания следует удалить с данной линии линия IRQ используется монопольно, то в качестве параметра ется значение NULL. Если линия IRQ IRQ. Если dev указыва­ используется совместно несколькими обработчиками прерываний, то вы должны указать для каждого из них уни­ кальный идентификатор. В случае успеха функция ненулевое - request_irq() возвращает нулевое значение. Если есть ошибка. В случае ошибки обработчик не регистрируется. Чаще всего возвращается значение выбранная линия IRQ E_BUSY, указывающее на то, что используется в другом обработчике прерывания и либо вы, либо автор другого драйвера забыл указать флаг IRQF_SHARED. Пример захвата прерывания: • • 1111· ································· ·····•"·························· ··-············
1 1 1а11а t\.1nux ................. . (1. Ofi1•afiщ 1,.:1 щн.·1н,11ш1111ii i f (request_irq(irqnum, inthndl r , printk(КERN_ERR IRQF_SНARED , "some_device", some_dev)) "some device : cannot register IRQ %d\ n", irqn); return -EIO; В этом примере в параметре irqnum указывается запрашиваемый номер IRQ. Параметр inthndlr определяет обработчик этой линии IRQ, которая может совместно использоваться, поскольку указан флаг IRQF_SHARED. Имя устройства "some_device", а в параметре some_dev передается значение идентификатора устройства dev. В случае ошибки мы пишем в лог ядра сообщение об ошибке . При выгрузке драйвера устройства из памяти компьютера необходимо от­ менить регистрацию обработчика прерывания и по возможности заблокиро­ вать линию IRQ. Для этого вызывается следующая функция : void free irq(unsigned int irq , void *dev) Если указанная линия IRQ используется монопольно, то эта функция уда­ ляет обработчик прерывания и блокирует линию IRQ. Если линия IRQ ис­ пользуется совместно с другими обработчиками прерываний, то удаляется обработчик, соответствующий параметру dev. Линия IRQ блокируется толь­ ко тогда, когда будет удален последний обработчик прерывания. При совместном использовании линии IRQ уникальный идентификатор требует­ ся для того, чтобы отличать друг от друга различные обработчики , связан­ ные с одним и тем же номером IRQ. Это позволяет в функции free_irq() уда­ лять нужный обработчик. В любом случае (совместного или монопольного использования линии IRQ), если параметр dev не равен значению NULL, то он должен соответствовать тому обработчику, которы й удаляется. Вызов функции 6.3. free_irq() должен выполняться из контекста процесса. Пишем собственный обработчик прерывания Как вы догадались, самое сложное - это не зарегистрировать обработчик, а написать его. Прототип функции-обработчика прерывания выглядит так: • .................................................................................·-1111
Ящю l,inux ...................... t\..inux static irqreturn t inthndlr(int irq , void *dev) Описание функции соответству~т прототипу второго аргумента handler, ко­ торый передается функции request_irq(). В первом параметре, irq, задается числовое значение номера линии запроса на прерывание , которую будет обслуживать обработчик. Несмотря на то, что это значение передается об­ работчику прерываний, оно используется очень редко, в основном в диагно­ стических сообщениях, выводимых в системный журнал. Второй параметр является уникальным идентификатором устройства, он должен совпадать с параметром dev, который передан функции request_irq() при регистрации обработчика прерывания. Функция-обраб отчик может возвращать одно из двух значений типа irqreturn: IRQ_ NONE и IRQ_HANDLED. Первое - если обработчик преры­ вания обнаружил , что устройство, которое он обслуживает, не является ис­ точником прерывания. Второе - если обработчик вы з ван правильно. Также IRQ_RETVAL(val). Если значение параметра val не равно нулю, то макрос возвращает значение IRQ_HANDLED, ина­ че возвращается з начение , равное IRQ_NONE. Эти специальные значения • можно использовать макрос позвол.яют проинформировать ядро о том, генерирует ли устройство пара­ зитные (т.е. необрабатываемые) прерывания . Если все обработчики пре­ рывания , которые обслуживают данную линию IRQ_NONE, то ядро ный тип возвращаемого значения, int . IRQ, возвращают значение может обнаружить проблему. Заметим, что этот стран­ irqreturn_t, просто соответствует типу Подстановка типа используется для того , чтобы обеспечить совместимость с более ранними версиями ядра, у которых не было подоб­ ной возможности . Настал момент истины: попробуем написать настоящий обработчик преры­ вания, который используется в драйвере часов реального времени clock, RTC). (real-time Это самый простой пример обработчика прерывания для кон­ кретного устройства. Код , рассмотренный далее, находится, как правило, в файле drivers/char/rtc.c. При загрузке драйвера RTC вызывается функция rtc_init(), которая инициа­ лизирует драйвер. Также она регистрирует обработчик прерывания, как по­ казано далее : • 1111-----·· .... ·-................ ··----.--.·------·. ---·. --·-------------.---.-------. •
t\.iпux ........... •...... . 1 JJaвa (1 . Обрабс111,а 11pt•pы11:11111i1 / * Регистрация обработчика rtc interrupt на r tc ir q * / if (request_ irq(rtc irq , rtc int e rrupt , IRQ F_SHARE D, "rtc", (void *)&rtc_ port)) { printk ( КERN_ERR " rtc : cannot register IRQ %d\n ", rt c_irq); return - EIO ; Номер прерывания хранится в переменной rtc_irq и зависит от конкретной аппаратной платформы . Для РС б отчик прерывания - это 8. Второй параметр указывает обра­ rtc_interrupt. Благодаря установке флага IRQF _ SHARED этот обработчик , по мере необходимости , может совместно с другими обра­ ботчиками использовать общую линию IRQ. Значение четвертого параметра определяет имя устройства - "rtc" . Поскольку устройство RTC может ис­ IRQ, в пятом параметре передается уникальное параметра dev. п ользовать общую линию ля устройства значение Обработчик прерывания выглядит так: s tatic irqreturn t rtc interrupt(int irq , void *dev ) { spin_lock(&rtc_lock); rtc irq_data += 0xl00 ; rtc_irq_data &= ~0xff ; rtc_irq_data 1= (CMOS_READ(RTC_ INTR_FLAGS ) & 0xF0 ); if (rtc status & RTC_TIMER_ON) mod_timer(&rtc_irq_timer , jiffies + HZ/rtc f re q + 2 *HZ / 1 00 ); spin unlock(&rtc lock) ; spin lock(&rtc task lock) ; if (rtc callback) rtc_callback->func(rtc_callback - >private_data ); spin_unlock(&rtc task_ lock); wake_up_interruptiЫe(&rtc_wait) ; kill fasync(&rtc_async_queue, SIGIO , POLL IN ); return IRQ_HANDLED; Данная функция вызывается всякий раз , когда наша система получает пре­ рывание от устройства RTC. Обратите внимание на вызовы функций спин­ бл окировок. Первая группа вызовов гарантирует, что к переменной data • rtc_irq_ не будет конкурентных обращений со стороны других процессоров на ..........................................-....................................... -1111
И , (JНI J,i1111\ ...................... t'1.1nux многопроцессорной машине. Вторая группа вызовов защищает в аналогич­ ной ситуации поля структуры rtc_callback. У переменной тип rtc_irq_data информация об устройстве unsigned /ong. RTC, В ней будет храниться которая обновляется при поступлении каждого прерывания и отражает состояние прерывания. Далее, если запу­ щен генератор периодических сигналов, обновляется значение системного таймера с помощью функции mod_timer(). Таймеры будут описаны в сле­ дующей главе. Во второй части кода, которая отделена пустой строкой , запускается функ­ ция обратноrо вызова, если таковая была установлена. Драйвер RTC позво­ ляет устанавливать данную функцию, которая может быть зарегистрирована извне. В результате она будет запускаться при каждом прерывании, которое приходит от устройства RTC. Функция-обработчик возвращает значение IRQ_HANDLED, чтобы указать, что прерывание от данного устройства корректно обработано. 6.4. API драйверов высокого уровня Ранее мы рассмотрели функции request_irq() и free_irq() - это основные функции для обработки прерывания. Первая из них запрашивает установ­ ку обработчика прерывания с заданным номером, вторая работчик . Кроме этих функций в таблице 6.1. - освобождает об­ приведены другие функции, которые могут вам понадобится . Описание всех этих функций можно найти по адресу: https ://www, kernel. org/doc/html/v4.12/core-api/kernel-api, html Таблица 6.1. Дополнительные АР/ высокого уровня Функция Описание Отключает выбранную линию прерывания. Включения и отключения являются вложенными. Эта функция ожидает завершения всех ожидающих disaЬ/e_irqO обработчиков IRQ для этого прерывания перед возвратом. Если вы используете эту функцию, удерживая ресурс, который может понадобиться обработчику IRQ, вы попадете в мертвую блоки- ровку (deadlock) ~, ....................................................................................
Глава r.linux ___ ______________ _ епаЬ/е_irqQ disaЬ/e_irq_ поsупсО (только SMP) synchronize_irqQ (только SMP) irq_set_irq_ typeQ 6. Обработка 11рерыва1111й Включает выбранную линию прерывания Отключает линию прерывания без ожидания. Функция должна вызываться из контекста прерывания Ждать ожидающих обработчиков IRQ (на других процессорах) Устанавливает тип триггера прерывания для задан- ного IRQ Включает/выключает режим управления питанием при пробуждении, по умолчанию этот режим irq_set_irq_wakeQ отключен. Включение данного режима позволяет указанному прерыванию пробуждать систему из состояния сна irq_ set_ handler_ dataO irq_set_chipQ irq_set_ chip_dataO 6.5. Устанавливает данные обработчика прерывания для заданного прерывания Устанавливает чип IRQ для заданного прерывания Устанавливает данные чипа для заданного прерывания Контекст прерывания При выполнении обработчика прерывания ядро находится в контексте пре­ рывания. Напомним, что контекст процесса - это режим, в котором ра­ ботает ядро, выполняя работу от имени процесса, например, выполнение вызова системной функции или потока ядра . • .--- ------ ------.-----.---.--.--. -----------.----. ----.-- ---.. -------.. --.---.--- --1111
Ядро ______________________ n..inux l.inux В контексте процесса макрос current возвращает указатель на связанную с ним задачу. Более того, поскольку при вызове функций ядра не происходит переключение конт екста процесса , система может приостановить выполне­ ние текущей задачи и переключиться на выполнение другой. В отличие от контекста процесса конт екст прерывания не связан ни с од­ ним процессом . По этому макрос current не имеет особого смысла, хотя он и возвращает указатель на процесс , выполнение которого было прервано. Поскольку в контексте прерывания нет сопровождающего его процесса, этот контекст нельзя перевести в состояние ожидания. Дело в том, что тогда бы нарушилась р 4 бота системного планировщика: нельзя перепланировать кон­ текст в котором нет задачи. Поэтому некоторые функции ядра не могут быть вызваны из контекста прерывания . Если функция может переводить процесс в состояние ожидания , то ее нельзя вызывать в обработчике прерывания, а это, в свою очередь , ограничивает набор функций, которые можно использо­ вать в обработчиках прерываний. Контекст прерывания является критичным ко времени выполнения, посколь­ ку на время обработки прерывания выполнение некоторого программного кода прекращается . Код же самого обработчика прерывания должен быть простой и быстрый . Использование в нем циклов проверки состояния чего­ либо (busy loop) крайне нежелательно , хотя и возможно . Это очень важный момент. Всегда следует помнить, что обработчик прерывания прерывает ра­ боту некоторого кода. В связи со своей асинхронной природой обработчики прерываний должны быть юlк можно более быстрыми и простыми. Макси­ мально возможную часть работы необходимо изъять из обработчика преры­ вания и переложить на его нижнюю половину, которая выполняется в более подходящее время . Во время конфигурации системы можно определить размер стека обработ­ чика прерывания . Исторически так сложилось , чtо обработчик прерывания не имел собственного стека . Вместо этого он должен был использовать стек ядра прерванного процесса. Стандартный размер стека ядра составляет две страницы памяти , что обычно соответствует 16 Кбайт - для 64-разрядных. Поскольку подразумевается, что обработчики прерываний используют об­ щий стек, они должны очень экономно расходовать память в этом стеке. Ко­ нечно, размер стека ядра будет всегда ограничен, поэтому при разработке любого кода ядра следует всегда иметь это в виду. • ID ---------------------------------------,-----------------.. ---.. --. -----. ------.-. •
1J 1ава n..inux _________________ _ 6.6. Функция (1. Обрабо1 ка 11рсрына1111ii do_ IRQ() Рассмотрим весь процесс обработки прерывания: 1. Первым делом устройство инициирует прерывание путем отправки элек­ трического сигнала контроллеру прерываний по аппаратной шине. Если нужная линия запроса на прерывание не запрещена, контроллер преры­ ваний отправляет сигнал прерывания процессору. В большинстве аппа­ ратных платформ это происходит путем подачи сигнала на специальный вход микросхемы центрального процессора. 2. Если прерывания в процессоре разрешены (иногда они могут быть запре­ щены), процессор завершает выполнение текущей машинной команды, запрещает прием новых прерываний, осуществляет переход на специаль­ ный адрес в памяти и начинает выполнять программный код, который на­ ходится по данному адресу. Сей заранее предопределенный адрес памяти был заранее сконфигурирован ядром и является точкой входа в обработ­ чики прерываний. 3. Вход в систему обработки прерываний в ядре начинается со строго опре­ деленной точки, так же, как и при вызове системных функций, вход в ядро выполняется через преопределенный обработчик исключительных ситуаций . Для каждой линии IRQ в памяти машины предусмотрена своя уникальная точка входа, куда и переходит процессор, после чего он на­ чинает выполнять расположенный там код. Именно таким образом ядро узнает о номере IRQ произошедшего прерывания. В точке входа сначала сохраняется в стеке значение номера прерывания и значения всех реги­ стров процессора, которые относились к прерванной задаче. После этого ядро вызывает функцию 4. Функция IRQ? do_IRQ() do_IRQ(). определяет, задан ли обработчик для данной линии Если нет, тогда вызывается функция ret_from _intr() и происходит возврат к выполнению прерванного кода. 5. Если обработчик прерывания задан, тогда вызывается функция IRQ_event(), handle_ IRQ, которая выполнит все обработчики для заданной линии а затем выполнит функцию ret_from_intr() для выхода из прерывания и возвращения к выполнению прерванного кода . .-------... ------------------.-----.-------------.. ----------------.. ---. -.-------81111
Я , tро Linux Функция ...................... n .i n ux do_IRQ() определена так : unsigned int do IRQ(struct pt regs regs) Поскольку соглашение о вызовах функций в языке С предусматривает раз­ мещение их аргументов в вершине стека, первоначальные значения всех ре­ гистров процессора, которые были сохранены ассемблерной программой в точке входа, передаются в функцию do_IRQ() через структуру pt_regs. Так как в этой стру!(Т)'ре также сохраняется значение номера прерывания, функ­ ция do_ IRQ() может его легко извлечь . После вычисления значения номера IRQ функция do_IRQ() отправляет уведомление о получении прерывания и запрещает генерирование прерываний по данной линии . Для обычных ма­ шин платформы РС эти действия выполняются с помощью функции mask_ and_ack_8295A(). Далее в функции do_ IRQ() выполняется проверка, что для данной линии IRQ зарегистрирован корректный обработчик прерывания , что этот обработчик разрешен и не выполняется в данный момент. Если все эти условия выпол­ няются , то вызывается функция kemel/irq/handle.c, handle_IRQ_event(), определенная в файле которая запускает установленные для данной линии IRQ обработчики прерывания. Код этой функции следующей: irqreturn_t handle irq_event(struct i rq_desc *desc ) { irqreturn_t ret ; desc- >istate &= ~IRQS PENDING ; irqd_set(&desc - >irq_ data , IRQD IRQ_I NPROGRESS ); raw_spin_ unlock(&desc - >lock ); ret = handle irq_event_percpu(desc) ; raw spin_lock(&desc - >l ock ); irqd_ clear(&desc - >irq_data , IRQD_ IRQ_I NPROGRE SS ); return ret ; • a i t ·········· · ·······································································
l ~ 1ава n..inux ................. . ()_ Обрабо1ка 11рсрыв.11111ii Поскольку сегодня машины , в основном , являются многопроцессорными , то сама функция handle_irq_event() передает управление функции handle_irq_ event_percpu(), которая, в свою очередь , возвращает значение , сгенерирован­ ное функцией _handle_irq_event_percpu(), которая и делает всю основную работу: i r qreturn t handl e irq_event_percpu (struct i rq_desc *desc) { irqreturn t r e tval ; retval = _handle irq event_percpu (desc) ; add_interrupt_ randomness (desc - >irq_data . irq) ; if ( ! irq_settings_no_debug (desc )) note inter r upt (desc , retval) ; return retval ; irqreturn t handle irq_event_percpu (st r uct irq_desc *desc) { irqreturn t retval = IRQ_NONE ; unsigned int irq = desc - >irq data . 1rq; s truct irqaction *action ; record irq_t i me (desc ); for each_ action of_desc(desc , acti o n) irqreturn t re s ; /* * force_irqthreads , о тметить */ if (irq_settings_can_thread(desc) && ! (action - >flags & (IRQF_NO_THREAD IRQF_ PERCPU IRQF_ ONESHOT))) lockdep_hardirq_threaded() ; Если это со ответствующим IRQ { будет передано под его образом . trace irq handler entry(irq , act1on) ; res = action - >handler(irq , action->dev_id) ; trace irq_handler_ exit(irq , action , res) ; if (WARN_ONCE (! irqs disaЬled ()," irq interrupts \ n ", irq , action - >handler)) local irq disaЬle() ; • %и handler %pS enaЫed ...................................--.... -.. --.. --... --..... -.--....... ---.... -----ID
И , 1рс1 l.i1111, ...................... ft1пux switch (res) { case IRQ_WAKE THREAD : /* Перехватьrвать но не драйверы, настроившие возвращающие функцию WAKE_THREAD, потока */ if (unlikely(!acti on - >thread_fn )) warn_no_thread(irq, action); break; _irq_wake thread(desc, action); break; default: break; retval 1= res; return retval; Функция ret_from_intr() и код входа в прерывание написаны на языке ас­ семблера. В этой функции проверяется, есть ли ожидающий запрос на пере­ планирование процессов. 6.7. Интерфейс Файловая система /proc/interrupts procfs - это виртуальная файловая система, которая существует только в памяти ядра и обычно монтируется на каталог Чтение или запись файлов в файловой системе procfs /proc. приводит к вызовам функций ядра, которые имитируют чтение или запись обычных файлов. Ха­ рактерный пример - файл /proc/intem1pts, который содержит статистику, связанную с прерываниями в системе. Ниже приведен пример вывода из этого файла на однопроцессорном персо­ нальном компьютере с двумя процессорами. • ID-.. ------------.-.--... ---.-.... -.-----.-.-.-------.---.. ---.---.. ---.. -. -----.---.
t.\.1пux ...... .. .. . ...... . 1 CPU0 CPUl 9 3 о о о о о о о 1: 6: 8: 9: 10 : 11 : 12 : 14 : 15: 24: 25 : о о 36586 123 08 ] 6: о о 27 : 28 : 17773575 8537896 22966247 3567412 29: о о о 32 о о 15 о о о о 30 : 20576365 о NMI : о о LOC : ~019558061 1070751773 SPU : О О PMI : о о I WI : 199664 251886 RTR : о о 43403577 RES : 36422980 CAL : 7991667 1712248 TLB: 402860 409492 Т RМ : о о THR : DFR: о о о о МС Е : о о МСР : 30468 30468 ERR : MIS : PIN : event NPI : PIW : 1:111а (, . Ofipafi111 i-:1 щ1t·р1.11ш11111i I O- APIC 1 - edge i 80 42 I O-APIC 6- edge iloppy I O- APIC 8-edge r tc0 I O-APIC 9- fas t e oi a c pi I O-APIC 1 0- fasteoi v irtio2 IO-APIC 11 - fasteoi uhci hcd : usЫ IO-APIC 12-edge i8042 IO-APIC 14 ~e ctge ata_piix IO-APIC 15 -e dge ata_piix PCI - MSI 65536 - edge virtiol -config PCI-MSI 65537-edge virtiol-virtqt.Eues PCI-MSI 49152-edge virtio0 -config PCI - MSI 49153 - edge virtio0 - input . 0 PCI-MSI 49154-edge virtio0-output.0 PCI-MSI 98304-edge virtio3 - config Pcr~мsr 98305 - edge v irtio3 - req.0 Non - maskaЫe interrupts Local timer interrupts Spurious interrupts Performance monitoring interrupt s IRQ work interrupts APIC ICR read retries Rescheduling interrupts Function call interrupts TLB shootdowns Thermal event interrupts Threshold APIC in t err up ts De ferred Err or APIC i nte rrupts Machi ne che ck exceptions м·achine chec k polls о о о о Pos t e d - i n t e r rupt notificat i o n о о о о Nes t ed p o s ted- interrupt e v ent Po s t ed- in t err upt wakeup event Первый столбец содержит номер линии IRQ. Линии IRQ для которых не установлен обработчик, не отображаются. Во втором столбце указывается общее количество полученных прерываний по данной линии IRQ. На много­ процессорных платформах здесь будет отображено несколько столбцов (по • ..--.-------------.. --.---..--_._--------------.------.. ---.. --.----.. --.----.---.--ID
Ядро l,inux ...................... n.inux числу процессоров), в которых указывается общее количество прерываний для каждого процессора. GleЫaravel .tt p о - roo\@85.193.80.192:22 - Bitv,se xterm - root@916661-ca932 16: - Рис. 6.1. Интерфейс х lproclinterrupts В следующем столбце (номер столбца зависит от количества процессоров, если процессор один , то это 3-ий столбец, если два - 4-ый и т.д.) указы­ вается контроллер прерываний, обрабатывающий данное прерывание. Зна­ чение XT-PIC соответствует стандартному программируемому контроллеру прерываний компьютера IВМ РС. Для систем, оснащенных устройством APIC, 1/0 для большинства прерываний в качестве контроллера прерываний бу­ дет указано значение 10-APIC-level или 10-APIC-edge. И, наконец, в послед­ нем столбце отображается имя устройства, связанного с прерыванием. Это имя передается в виде параметра devname функции request_irq(), как гово­ IRQ совместно используется несколь- рилось выше . Если какая-то из линий • ID- ------------"" -""""" ----"----. ----.--. ----------.-----------------------------.. -.
1 , ,ана n..1nux ................. . кими устройствами (как IRQ4 (1. Ofipaбo 11,а 11pt•111,шa1111ii в нашем примере), то в последнем столбце будут перечислены имена всех зарегисrрированных для данной линии IRQ устройств. ··;··············································································-ID
Глава 7. Таймеры и отслеживание хода времени
Sl11po l,i1111x 7.1. ....................... n.1nux Учет времени в ядре Ядро помимо всего прочего, занимается также и учетом времени. Причем учет времени является одной из важнейших функций ядра, поскольку в ядре есть множество функций, которые запускаются по сигналам времени, а не по событиям. Другими словами, есть функции , которые запускаются, если произошло какое-то событие . А есть функции, которые вызываются по жест­ кому графику, например, 100 раз в секунду. Ядро может запланировать ра­ боту на выполнение в момент времени, который наступит спустя 1 секунду относительно текущего момента . Говоря о планировании времени , нужно разделять понятия абсолютного и относительного времени . Если нужно выполнить некоторую работу в буду­ щем, скажем, спустя 1 минуту относительно текущего момента - учет абсо­ лютного времени не нужно, только отн о сительного , то есть относительно текущего момента нужно отсчитать 60 секунд. А вот е сли нужно выполнить работу в определенное время, например, в 23 :00, тогда нужен учет абсолют­ ного времени. аа- • -------------------------------.----.----------.---... -....... -............... -.. 1
~lnux ................. . 1 1,11\, 1 7 ·1а1нн·р1.1 11 111 ('. l(' Жllll:11111(' \11, 1:1 IIJl('\1('1111 Имеются отличия в реализации обработчиков событий, возникающих пери­ одически, и тех, которые планируются на выполнение ядром в некоторый фиксированный момент времени в будущем. События, возникающие пе­ риодически (скажем, каждые 50 мс), генерируются системным таймером. Последний представляет собой программируемое аппаратное устройство, которое генерирует аппаратные прерывания с фиксированной частотой. В обработчике этого прерывания, которое называется прерыванием от тайме­ ра (timer interrupt), обновляется значение системного времени и выполняют­ ся периодические действия. Системный таймер и его прерывания являются основной движущей силой, отвечающий за работу операционной системы Linux. Также мы . поговорим о динамических таймерах (dynamic timers) ___: средствах, позволяющих планировать события, которые выполняются один раз, после истечения некоторого интервала временц . С точки зрения компьютера концепция времени является неопределенной. Чтобы получать информацию о текущей дате и управлять системным вре­ менем, ядро должно взаимодействовать с системным аппаратным обеспече­ нием. Данное "железо" содержит системный таймер, используемый ядром для измерения прошедшего времени. Внутри системного таймера находит­ ся кварцевый резонатор, обеспечивающий очень точное значение периода вырабатываемых импульсов. Такой же резонатор используется в цифровых электронных часах или тактовом генераторе процессора. Системный тай­ мер вырабатывает эти импульсы с заранее заданной частотой, на­ зываемой частотой импульсов. Как только истекает период очередного импульса, процессору посылается прерывание от таймера, в результате чего вызывается специальный обработчик прерывания. Ядру известна частота импульсов системного таймера, поэтому оно может вычислить интервал времени, прошедший между двумя прерываниями от таймера. Данный интервал времени между двумя импульсами системного таймера называется периодом следования импульсов и измеряется в долях секунды и равен обратному значению частоты системного таймера. Абсо­ лютное значение времени соответствует текущему значению времени суток и очень важно для работы пользовательских приложений. Ядро в состоянии отследить это время просто потому, что оно обрабатывает прерывания от таймера. В ядре предусмотрено семейство системных функций, позволяю­ щих пользовательским приложениям получать информацию о дате и време­ ни дня. Время непрерывной работы системы (system uptime) является относитель­ ным и отсчитывается от момента последней перезагрузки системы. Оно • • ........ ........... .. ..................... ... ..... ... .............................. . .
и ' IIНI 1.ill 11 \ ......... . ............. r.l1nux используется как в системных, так и в пользовательских приложениях . Во многих программах требуется знать интервал времени , прошедший между двумя событиями. Проще всего его измерить как разность между двумя зна­ чениями времени непрерывной работы системы, считанными в нужные мо­ менты. Прерывания от таймера очень важны для управления работой всей опера­ ционной системой. Существует большое количество функций ядра, которые система запускает в зависимости от хода времени. Также ряд функций запу­ скается периодически по сигналу прерывания от таймера, например , обнов­ ление значени.й времени, обновление абсолютного значения времени, запуск обработчиков всех динамических таймеров и т.д . Многие из этих функций выполняются при каждом прерывании таймера, то есть работа делается с частотой системного таймера. 7 .2. Таймеры ядр а Когда нам нужно запланировать действия на позднее время без блокирова­ ния текущего процесса до наступления момента времени , лучшим инстру­ ментом являются таймеры ядра. Такие таймеры используются для планиро­ вания выполнения функции в определенное время в будущем , основываясь на тактовых тиках, и могут использоваться для различных задач - напри­ мер, опрос устройства путем проверки его состояния через регулярные про­ межутки времени, когда оборудование не может генерировать прерывания . Другим типичным использованием таймеров ядра является отключение двигателя HDD или завершение другой длительной операции выключения . В таких случаях задержка возвращения из c/ose создала бы ненужные (и неожиданные) трудности для прикладной программы. Наконец, само ядро использует таймеры в ряде ситуаций , включая реализацию schedule_timeout. Таймер ядра является структурой данных , которая инструктирует ядро для выполнения заданных пользователем функций с заданным пользователем аргументом в заданное пользователем время . Реализация находится в timer.h> и kemel/timer.c <linux/ и более подробно поговорим об этом далее в этой главе. Функции, которые были запланированы для запуска, почти наверняка не ра­ ботают, пока выполняется процесс , который их регистрирует. Вместо этого , они запускаются асинхронно. До сих пор все, что мы сделал и в наших при- 111-....... --... --....·... -... -... -... --... --... -.. -... -.... --........ -........ -... -.'
t.\.1пux .................. . мерах драйверов - 1 1, 11 1. 1 7 1а11\н· р1.111111cн· :.i-i111a1111t· ,н 1а 111н· \lt·1111 это работа в контексте процесса, выполняющего систем­ ные вызовы. Когда запущен таймер, процесс, который запланировал его, мо­ жет спать, выполняться на другом процессоре, или, что вполне возможно, вообще завершиться. Такое асинхронное выполнение напоминает то, что происходит, когда вы­ полняется аппаратное прерывание. В самом деле, таймеры ядра работают как результат "программного прерывания". При запуске в атомарном кон­ тексте этого рода на ваш код налагается ряд ограничений. Функции таймера должны быть атомарными всеми способами, но есть некоторые дополни­ тельные вопро~ы, вызванные отсутствием контекста процесса. Теперь мы введем эти ограничения; они будут рассматриваться снова в нескольких местах в последующих главах. Повторение делается потому, что правила для атомарных контекстов должны усердно соблюдаться, или система окажется в тяжелом положении. Некоторые действия требуют для выполнения кон­ текст процесса. Когда вы находитесь за пределами контекста процесса (то есть в контексте прерывания), нужно соблюдать следующие правила: • Не разрешен доступ к пользовательскому пространству. Поскольку от­ сутствует контекст процесса, нет пути к пользовательскому пространству, связанному с любым определенным процессом. • Указатель current не имеет смысла в атомарном режиме и не может быть использован, поскольку соответствующий код не имеет связи с процес­ сом, .который был прерван. • Не может быть выполнено засыпание или переключение. Атомарный код не может вызвать schedule или какую-то из форм wait_event и не может вызвать любые другие функции, которые могли бы заснуть. Например, вызов kmalloc( ... , GFP_КERNEL) идет против правил. Семафоры также не должны быть использованы, поскольку они могут спать. Код ядра может понять, работает ли он в контексте прерывания, вызова~ функции in_inteпupt( ), которая не имеет параметров и возвращает ненуле­ вое значение, если процессор в настоящее время работает в контексте пре­ рывания, аппаратного или программного. Функцией, связанной с inteпupt(), является in_atomic(). in_ Она возвращает ненулевое значение, когда переключение не допускается; это включает в себя аппаратный и программ­ ный контексты прерывания, а также любое время, когда удерживается '----........................................................................... ··ID
И . 1ре1 l .illll\ ....................... n.1nux спин-блокировка. В последнем случае, current может быть действительным, но доступ к пользовательскому пространству запрещен, поскольку это мо­ жет привести к переключению. Каждый раз , когда вы используете rupt(), in_interin_atomic() тем, что вы объявлены в <asm/hardirq.h>. следует рассмотреть вопрос, не является ли действительно имеете в виду. Обе функции Еще одной важной особенностью таймеров ядра является то, что задача мо­ жет перерегистрировать себя для запуска снова в более позднее время. Это возможно , потому что каждая структура timer_list не связана со списком ак­ тивных таймеров перед запуском и , следовательно, может быть немедленно перекомпонов·ан~ где угодно. Хотя переключение на одну и ту же задачу сно­ ва и снова может показаться бессмысленной операцией, иногда это бывает полезно. Например, это может быть использовано для реализации опроса устройств. Кроме того, стоит знать, что в многопроцессорных системах таймерная функция (функция, запускаемая таймером) выполняется тем же процессо­ ром, который ее зарегистрировал для достижения лучшего расположения кэша, когда это возможно . Поэтому таймер, который перерегистрирует себя, всегда запускается на том же процессоре. 7 .3. API таймера Ядро предоставляет драйверам ряд функций для декларации , регистрации и удаления таймеров ядра. Ниже приводится фрагмент кода, показывающий основные стандартные рлоки: #include <linux /timer.h> struct timer list /* . .. * / unsigned long expires ; void (*function) (unsigned l o ng) ; unsigned long data ; }; void init_ timer(struct timer_list *timer) f struct timer_list TIMER_INITIALIZER( function , _expires , ... void add_timer (struct timer_list * timer) ; int del_timer(struct timer_list * timer) ; . . . -... --.. data ); • ---. ---. ---....... . -... -. -. -... --... -... --.. ---.. --... -... -... --.. -.. -.
l . 1 ана 7. n..inux ................. . Taii,1cpы 11 OIC. ICЖIIВallllC \О, Щ вpc\lCIIII Структура данных включает в себя больше полей, чем показано в нашем фрагменте , но продемонстрированные три поля предназначены для доступа снаружи кодом таймера. Поле expires представляет значение таймер ожидает для запуска; в это время функция данными data jiffies, которое _ function вызывается с в качестве аргумента . Если нужно передать много объектов в аргументе, можно собрать их в единую структуру данных и передать указа­ тель, приведя к unsigned long, это безопасная практика на всех поддержива­ емых архитектурах и она довольно распространена в управлении памятью. Значение expi~es не является типом jiffi.es_ 64, поскольку не ожидается , что таймер сработает очень далеко в будущем и на 32-х разрядных платформах 64-х разрядные операции медленны. Структуры должны быть проинициализированы перед использованием. Данный шаг гарантирует, что все поля правильно настроены, в том числе те, которые не видимы для вызывающего. Инициализация структуры может быть осуществлена с помощью вызова init_timer или присвоением TIMER_ INIТIALIZER статической структуре, в соответствии с вашими потреб­ ностями . После инициализации , но перед вызовом add_timer(), можно из­ менить три открытых поля . Чтобы отключить зарегистрированный таймер до его истечения, вызовите функцию примера, /proc/jitimer del_timer(). Модуль jit включает файл (для "только по таймеру") , который возвращает стро­ ку заголовка и шесть строк данных . Строки данных показывают текущее окружение, где выполняется код; первая создается файловой операцией остальные - read, по таймеру. Следующий вывод был записан во время компиля­ ции ядра: ca t /proc/ji t imer t i me de l ta in irq 33565837 о о 33565847 10 1 33565857 10 1 33565867 1 0 1 33565877 10 1 33565887 10 1 В этом выводе, поле delta time pi d 1269 1271 1 273 1273 1274 1274 cpu command о cat sh о о сррО о сррО о cc l ccl о является значениемji.ffiеs, когда код запускается, является изменением jiffies относительно предыдущей строки, это логическое значение, возвращаемое • inirq in_interrupt, pid и command относят- ·-··-·-····--------···------ ------------------··--····--······-········-·········· -
И IIНI I ................... . ... r.t.iпux illll\ ся к текущему процессу и ери является номером испол ьзуемого процессора (всегда О на однопроцессорных системах) . Если вы прочитаете /proc/jitimer при выгрузке системы , вы обнаружите , что контекстом таймера является процесс О , задача простоя вается "swapper" (idle), которая назы­ ("планировщик своппинга") в основном по историческим причинам . Таймер используется для генерации данных дые 1О /proc/jitimer по ум олчанию каж­ тикав, но при загрузке модуля можно изменить значение , установив параметр tdelay (timer delay, задержка таймера) . Следующий · отрывок кода показывает часть jit, связанную с таймером jitimer. Когда процесс пытается прочитать наш файл , мы устанавливаем тай­ мер следующим образом: unsigned l ong j = jiffies; /* запо лняе м данные для нашей таймерной data - >p re vjiffies = j ; data - >buf = buf2 ; data->loops = JIT ASYNC LOOPS ; функции* / /* ре г истрируем таймер*/ data - >timer . data = (unsigned long)data ; data - >timer . function = jit_timer_fn; data - >timer .e xpires = j + tdelay ; /*параметр* / add_ time r ( &data - >timer) ; /* ждем заполнения буфера* / wait_event_interruptiЬle(data - >wait, API !data- >loops) ; таймера включает в себя несколько больше функций, ч ем те , которые введены выше . Следующий набор завершает список предложения ядра : int mod_timer(struct timer list *timer , u nsigned l o ng expires) ; Данная функция осуществляет обновление времени истечения срока тай ­ мера. Функция mod_ timer() может быть вызвана при неактивных таймерах, также, как обычно используется add_timer(). Рассмотрим следующую функцию: • llt- -----------. --------------------------------------------------------------------.
1 n.1nux ................. . 1, 11 \, 1 1 1.111\lt' lll •I II IIICH' Жlll\atlllt' \111:1 Bpt'\1('1111 int del_timer_ sync(struct timer_list *timer); Работает как ц del_timer(), но также гарантирует, что когда она вернется, таймерная функция не запущена на каком-то процессоре. Данная функция используется, чтобы избежать состояний состязания на многопроцессор­ ных системах, и аналогична del_timer() на однопроцессорных ядрах. Этой функции в большинстве ситуаций следует отдавать предпочтение перед del_ Она может "заснуть", если вызывается из неатомарного контекста, timer(). но наход~тся в активном ожидании в других ситуациях. Будьте очень осторожны, вызывая ровок, - del_timer_sync() при удержании блоки­ если таймерная функция попытается получить ту же блокировку, система может заблокироваться. Если эта таймерная функция перерегистри­ рует себя, вызывающий должен сначала убедиться, что эта перерегистрация не произошла ; обычно это достигается установкой флага "shutting down" ("выключить") , который проверяется таймерной функцией . Следующая функция - timer_pending(): int timer_pending(const struct timer list * timer) ; Возвращает истину или ложь, чтобы показать, будет ли таймер в настоящее время запланирован для запуска, чтением одной из скрытых полей струк­ туры. 7.4. Реализация таймеров ядра Обычно вам не нужно знать , как реализованы таймеры ядра, чтобы их ис­ пользовать. Но их реализация интересна и стоит посмотреть на их внутрен­ ности. Реализация счетчиков была разработана, чтобы соответствовать следующим требованиям и предположениям: • • Управление таймером должно быть максимально легким . ··················································································-
Я , tро (,i1111x • ___ ___ ...... _______ .... n.inux Конструкция должна позволять увеличивать количество активных тай­ меров. • Большинство таймеров истекают в течение нескольких секунд или, самое большее, минут, в то время как таймеры с длительными задержками до ­ вольно редки. • Таймер должен работать на том же процессоре, который его зарегистри­ ровал. Решение, созданное разработчиками ядра, основано на копии структуры данных для каждого процессора. Структура timer_list включает в себя ука­ base. Если base является затель на такую структуру данных в своем поле NULL, таймер не запланирован для запуска ; в противном случае, ук-азатель говорит, какая структура данных (и , следовательно, какой процессор) за­ пускает его. Всякий раз, когда код ядра регистрирует таймер (через add_timer или mod_ timer), операции в конечном итоге выполняются internal_add_timer (в kemeU timer.c), которая, в свою очередь, добавляет новый таймер в двусвязный спи­ сок таймеров в рамках "каскадной таблицы", связанной с текущим процес­ сором. Каскадные таблицы работают так : если таймер истекает в следующих тиках от О до 255, он добавляется в один из 256 списков, посвященных таймерам малого диапазона, используя самые младшие биты поля expires. Если он истекает дальше в будущем (но до 16384 тиков), он добавляется в expires. Для таймеров истека­ ющих еще позже, тот же прием используется для битов 15-20, 21-26 и 2731. Таймеры с полем времени окончания еще дальше в будущем ( что может один из 64 списков на основе битов 9-14 поля случиться только на 64-х разрядных платформах) делятся на задержки со значением Oxffffffff и таймеры с expires в прошлом планируются для запуска в следующем тике таймера (таймер , который уже истек, иногда может быть зарегистрирован в ситуациях высокой нагрузки, особенно если вы работаете с вытесняющим ядром) . После запуска _run_timers, он запускает все отложенные таймеры на теку­ щий тик таймера . Ecлиjif.fies в настоящее время является кратной 256, функ­ ция также заново делит один из списков таймеров следующего уровня на 256 списков короткого диапазона, возможно каскадируя один или несколь­ ких других уровней также в соответствии с битовым представлениемjif.fiеs . • 118----- -- -------. --..... ----- -- ------ --- --..... -- ---- --....... -- ----- -- ------. ---- --·
n.inux .................. . [ ; ~ава 7. Taiiмcp1,1 и OICJ ICЖIIB.НIИC Xl))ta нрсмс1111 Это подход, хотя и чрезвычайно сложный на первый взгляд, выполняется очень хорошо как с несколькими таймерами, так и с большим их числом. Время, которое необходимо для управления каждым активным таймером, не зависит от количества уже зарегистрированных таймеров и ограничено несколькими логическими операциями над двоичным представлением поля expires. Накладным расходом, связанным с этой реализацией, является па­ мять для 64 512 заголовков листов (256 краткосрочных списков и списков более длительных диапазонов), то есть Функция _run_timers, как показано /proc/jitimer, 4 Кб 4 группы из памяти. будет запущена в атомар­ ном контексте. _Кроме уже описанных ограничений, это приносит интерес­ ную особенность: таймер истекает только в заданное время, даже если вы не работаете на вытесняющем ядре и процессор занят в пространстве ядра. Вы можете видеть, что происходит, когда вы читаете режиме и /proc/jitimer с высоким приоритетом. /proc/jitbusy в фоновом Хотя система кажется прочно заблокированной системным вызовом с активным ожиданием, таймеры ядра все же работают нормально. Таймер ядра далек от совершенства, он страдает от дрожания и других арте­ фактов, вносимых аппаратными прерываниями, а также другими таймерами и другими асинхронными задачами. Хотя таймер, связанный с простым циф ­ ровым вводом/выводом, может быть достаточен для таких простых задач, как запуск шагового двигателя или другой любительской электроники, это обычно не подходит для производственных систем в промышленных усло­ виях. Для выполнения таких задач вам, скорее всего, придется прибегнуть к расширению ядра для реальнQго времени. •.......................... -...·.· ............................--....................tlll •
Глава 8. Управление памятью
Sl ,tJIO J,i1111x ...................... n.1nux Подсистема работы с оперативной памятью в достаточно многогран­ Linux - ная конструкция. Чтобы разобраться в ее деталях, нужно целенаправленно погрузиться в тему, с обязательным чтением исходников ядра, но это нужно не каждому. Для разработки и эксплуатации серверного программного обеспечения важно иметь хотя бы базовое представление о том, как она ра­ ботает, но, как показывает практика, не многие администраторы и разработ­ чики обладают подобными знаниями. 8.1. Какая бывает память? 8.1.1. Физическая и виртуальная Начнем с самих азов. Представим, что у нас есть сервер (без разницы физический или VDS), скажем, с 16 Гб оперативной памяти . Что это значит? Именно столько в нем есть физической памяти. Для тех, кто забыл: физи­ ческая память (или "ОЗУ 1 ", "RAM2", "оперативка") - это энергозависимая память, установленная в компьютере. Для ее работы требуется непрерывный поток электричества. Перебои с электропитанием или внезапное выключе- .. 2 Оперативное запоминающее устройство Random Access Memory • . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .
1т111а Х . Yнp,111. ll'Ш1l' ШIMSI 11,Ю r.t..inux ................. . ние компьютера могут привести к стиранию хранящихся в ней данных. Кро­ ме того , эта память является линейно адресуемой. Другими словами, зна­ чения адресов памяти увеличиваются линейным образом. На физическом компьютере оперативная память представляет собой набор модулей ( 1 или более) памяти, установленных в слоты на материнской плате компьютера (рис. 8.1). Рис. 8.1. Оперативная па.мять Задача распределения доступных ресурсов между исполняемым программ­ ным обеспечением, в том числе и физической памяти , лежит на плечах операционной системы, в нашем случае Linux. Для обеспечения иллюзии полной независимости , она предоставляет каждой из программ свое неза­ висимое виртуальное адресное пространство и низкоуровневый интерфейс работы с ним. Такая схема избавШ!"ет их от необходимости знать друг о дру­ ге, размере доступной физической. памяти и текущей ее занятости. Адреса в виртуальном пространстве процессов называют логическими. Для отслеживания соответствия между физической и виртуальной памятью ядро Linux использует иерархический набор структур данных в своей слу­ жебной области физической памяти (только оно работает с ней напрямую), а также специализированные аппаратные контуры, которые в совокупности называют 8.2 показано место MMU в структуре управления TLB на данном рисунке - это буфер преобразований (Translation Lookaside Buffer). О нем мы еще поговорим. MMU 3 . На рис. памяти. Аббревиатура • Memory Management Unit . .........."-.""" .. "" ... ""." "" -.. "" .... ". -... "" .. """. -"... "" .. """ .. """." "". -"" "-."" 1111
И 1ро ...................... n.,пux l .i,111, Процессор Фto> . ,..pect1 Фма. '-Afl8C Фма. "-АР8С Ф,,3 _ '-АJ)К 12 13 '4 Физи чески й адрес ФIQ. ,..pecflN ОЗУ Рис. 8.2. MMU и физическая память Следить за каждым байтом памяти в отдельности было бы накладно, поэтому ядро оперирует достаточно большими блоками памяти ми, типовой размер которых составляет 4 килобайта (4096 - страница­ байт). На аппаратном уровне, как правило, есть поддержка дополнительного уров­ ня абстракции в виде "сегментов" (?Перативной памяти, с помощью которых можно разделять программы на части. В отличие от других операционных систем, в Linux она практически не используется - логический адрес всегда совпадает с линейным ( адресом внутри сегмента, который сконфигурирован фиксированным образом). Физическая страницы память разделяется на (page). отдельные фрагменты, называемые Практически вся внутренняя системная обработка памяти производится на постраничной основе . Размер страницы зависит от исполь­ зуемой архитектуры. Обычно размер страницы равен asm/page.h определена константа PAGE_SIZE, 4096 байт или 4 Кб. В задающая размер страницы для используемой архитектуры. Для 64-битных систем нужно заглянуть в файл page_64.h. Если посмотреть на адрес памяти (без разницы какой - виртуальный или фи­ зический), можно увидеть , что он делится на номер страницы и смещение внутри этой страницы. Например, если используются страницы по байт, 12 младших значащих бит являются 4096 смещением, а остальные , старшие биты, указывают номер страницы. Если отказаться от смещения и сдвинуть оставшуюся часть адреса вправо, результат называют номером страничного 1111-.----------------.---.----.-------.. -------.---.---------... -.. --.. -.. ----.----_,
1 1а11а Х . ~ IIJ),Ш. lt'llllt' 11а,н111,Ю n..inux ................. . блока (page frame number, PFN). Сдвиг битов для конвертации между но­ мером страничного блока и адресами является довольно распространенной операцией; макрос PAGE_SHIFT сообщает, сколько битов должны быть сме­ щены для выполнения этого преобразования. 8.1.2. Файловая и анонимная У приложений существует много способов выделить себе память для тех или иных ·нужд. Высокоуровневые языки программирования и библиотеки часто прячут от разработчиков, какой из них в реальности использовался и другие детали (хотя их всегда можно это узнать с помощью strace). Если углубляться в особенности каждого доступного варианта, можно написать книгу только по управлению памятью. Вместо этого предлагаем разделить их на две, на мой взгляд, крайне важные группы по тому, какую память они выделяют: • Файловой памяти однозначно соответствует какой-либо файл или его часть в файловой системе . Первым делом в ней находится исполняемый код самой программы. Для прикладных задач можно запросить отобра­ жение файла в виртуальное адресное пространство процесса с помо­ щью системного вызова mmap() - после чего с ним можно работать как с любой другой областью памяти без явного чтения/записи. Что будет при этом происходить с данными в файловой системе и что будут видеть дру­ гие процессы "отобразившие" этот же файл зависит от настроек. • Любую другую выделенную память называют анонимной, так как ей не соответствует никакой файл. Сюда попадают как переменные в стеке, так и области , выделенные с помощью функций вроде malloc (к слову, за сце­ ной для выделения больших блоков памяти они обычно тоже используют mmap с особым набором настроек, а для всего остального - brk/sbrk или выдают ранее освобожденную память). На первый взгляд отличия не выглядят чем-то особенным, но тот факт, что области файловой памяти именованы, позволяет операционной системе эко­ номить физическую память , порой очень значительно , сопоставляя вирту­ альные адреса нескольких процессов , работающих с одним и тем же фай­ лом , одной физической странице в памяти . Это работает прозрачно, начиная • ...................................... ..... .................... ... ... .. .. ... .........
И , tfНI l ,illll\ ...................... n.1nux от кода запущенных нескольких копий приложений, заканчивая специально сконструированными под эту оптимизацию систем. 8.1.3. Вытесняемая и невытесняемая память Суммарный объем используемой виртуальной памяти всех программ запросто может превышать объем доступной физической памяти. При этом в каждый конкретный момент времени приложениями может использовать­ ся лишь небольшое подмножество хранимых по виртуальным адресам дан­ ных. Это означает, что операционная сисrема может откладывать не исполь­ зуемые в данный момент данные из оперативной памяти на жесткий диск ("вытесняя"" их из памяти), а затем при попытке к этим данным обратиться - скопировать обратно в физическую оперативную память. Этот механизм официально называется ло подразумевают личие в том, что в major page fault, но под просто page fault как прави­ тоже его, так как minor page fault мало кого заботит (от­ случае minor ядру удается найти запрашиваемые данные уже загруженньiми в память с какой-то другой целью и обращения к диску в итоге не происходит). На время восстановления запрашиваемых приложением данных его выпол­ нение прерывается и управление передается ядру для выполнения соот­ ветствующей процедуры . Время, которое потребуется, чтобы приложение смогло продолжить свою работу, напрямую зависит от типа используемого жесткого диска: • Прочитать 4Кб данных с обычного серверного жесткого диска занимает порядка 1О мс, 7200rpm при хорошем стечении обстоятельств чуть мень­ ше . Если вытесненных страниц оказывается много, запросто могут на­ бегать заметные доли секунды (как условным пользователям, так и на внутренних приборах, в зависимости от задачи). клические pagefaults, Особенно опасны ци­ когда есть две или более регулярно используемые области памяти, которые вместе не помещаются в физическую память, поэтому бесконечно вытесняют друг друга туда-обратно. При этом диск вынужден делать честный seek, что само по себе тоже может быть некста­ ти . Например, если с этим же диском работает какая-либо база данных . • Если используется отсутствия SSD, то ситуация несколько более радужная механического движения примерно на порядок меньше, около аналогичная 1 мс операция - из-за занимает • или ее доли, в зависимости от • 1111··················································································
1с1а11а ainux ................. . Х. У11рав~ 1с1111с шtl\HJ I ыо типа и конкретной модели диска. Но годы идут, а SSD так и остаются нишевым, компромиссным продуктом по цене-объему. Если настольные варианты SSD стали дешевле , то цены на серверные дешевле не стали. Да и нужно учитывать не только цену одного гигабайта хранимой информа­ ции, но и ресурс . Примечание. Для сравнения: если бы страница уже была в па­ мяти, то при обращении к ней счет шел бы на сотни наносекунд . Это почти на 4 порядка быстрее, чем Примечание о ресурсе SSD. pagefault, даже на SSD . В своем распоряжении автор этой книги имеет два ноутбука. Первый покупался очень давно и с целью повышения производительности на него был установлен SSD от Кingston на 480 Гб. Думаю, по размеру вы догадались, что стоил он тогда, наверное, дороже , чем весь ноутбук. Так вот этот SSD проработал чуть более года. На втором ноутбуке был изначально установлен проработал свои 3-4 SSD Samsung Evo, который честно года, а потом при запуске система начала "ругаться", что его срок вышел . Никаких ошибок S.M.A.R.Т. не показывал, просто один из счетчиков ных часов - - количество отработан 0 превысил запрограммированное значение. Видимо, даже сам производитель не ожидал, что он столько проработает. Пришлось заменить его новый во избежание потерь информа­ ции. К слову, оригинальный жесткий диск на первом ноутбуке до сих пор отлично работает. Вот и посчитайте стоимость н,е только гигабайта информации при покупке нового устройства , но и то , что за один и тот же срок HDD SSD вы поменяете несколько раз, а будет работать. Поэтому далеко не все администраторы на серверах спешат переходить на SSD (хотя на дворе уже год), а предпочитают проверенные и более ресурсные 2023 HDD. Тем более, если речь идет о сервере, где частота обращений к диску в разы выше, чем на пользовательском ноутбуке. Стоит отметить, что с точки зрения приложения все это прозрачно и являет­ ся внешним воздействием, то есть может происходить в самый не подходя­ щий, с точки зрения решаемой им задачи, момент. Думаю, понятно, что приложения , которым важна высокая производитель­ ность и стабильное время отклика, должны избегать pagefault'oв всеми доступными методами, к ним и перейдем . • ........... ..... ....... ........... .. ... ............................................ .
Я , {ро l,inux _____ _____ ___ __ . ____ ___ n.inux 8.1.4. Разные типы ОС адресов как уже было отмечено, является системой с виртуальной памя­ Linux, тью, а это означает, что адреса, видимые пользовательскими программами, не соответствуют напрямую физическим адресам , используемым оборудо­ ванием. Виртуальная память вводит слой абстракции, позволяющий ряд приятных вещей. Так, при использовании виртуальной памяти программы, выполняю­ щиеся в системе, могут выделить гораздо больше памяти, чем доступно фи­ зически; более того , даже один процесс может иметь виртуальное адресное пространство больше физической памяти системы. Виртуальная память по­ зволяет также программе использовать разные ухищрения с адресным про­ странством процесса , в том числе отображение памяти программы в память устройства. ОС Linux имеет дело с несколькими типами адресов , каждый со своей соб­ ственной семантикой. К сожалению , в коде ядра не всегда четко понятно, .ка­ кой именно тип адреса используется в каждой ситуации , так что разработчик должен быть осторожным. Разберемся , какие типы адресов используется в Linux: • Пользовательские виртуальные адреса - •обычные адреса, видимые программами пространства пользователя. Такие адреса могут быть 32 или 64 разрядными , в з ависимости от архитектуры (не стоит забывать, что Linux может запускаться на разнообразных мини-компьютерах, встроенном оборудовании , которое все еще 32-битное, в отличие от пер­ сональных компьютеров и серверов , которые уже давно стали 64-битны­ ми). Каждый процесс имеет свое виртуальное адресное пространство. • Физические адреса - адреса, которые используются между процессо­ ром и памятью системы. В зависимости от архитектуры, они также могут быть • 32 или 64 разрядными. Адреса шин - адреса, используемые между периферийными шинами и памятью. Зачастую они такие же, как физические адреса, используемые процессором, но это не обязательно так. Некоторые архитектуры мо­ гут предоставить бл ок управления па.1v1ятью ввода/вывода (1/0 memory management unit, IOMMU), который переназначает адреса между шиной и оперативно й памятью. IOMMU может сделать жизнь легче несколькими способ ам и (например , делая разбросанный в памяти буфер выгля дящи ~ 1 1 8 ----·-----------··--···- -·-- ------·---·---···--- -- --·---·· --···-··- -·· ·- -··- ---··'
1 1 1ава Х . Y111J:шлt•1111t• ш1м1111.ю n.1nux ................. . непрерывным для устройства) , но программирование IOMMU является дополнительным шагом, который необходимо выполнить при настройке DMA операций. • Конечно , адреса шин сильно зависят от архитектуры. Логические адреса - составляют обычное адресное пространство ядра. Такие адреса отображают какую-то часть основной памяти и часто рас­ сматриваются как физические адреса. В большинстве архитектур логиче­ ские адреса и связанные с ними физические адреса отличаются только на постоянное смещение. Логические адреса обычно хранятся в перемен­ ных типа unsigned long или void *. Память, возвращаемая kmalloc, имеет логичеСКf!Й адрес ядра. • Виртуальные адреса - похожи на логические адреса тем, что они явля­ ются отображением адреса пространства ядра на физический адрес. Сто­ ит отметить, что виртуальные адреса ядра не всегда имеют линейную, взаимно-однозначную связь с физическими адресами, характеризующую логическое адресное пространство. Все логические адреса являются вир­ туальными адресами ядра, но многие виртуал ьные адреса ядра не явля­ ются логическими адресами. Так, например, память, выделенная vmalloc, имеет виртуальный адрес (но без прямого физического отображения). Функция kmap ( описываемая далее в этой главе) также возвращает вир- туальные адреса. Виртуальные адреса обычно хранятся в переменных указателей. На рис. 8.3 показаны типы адресов, используемые в Linux. При этом не окра­ шена область физической памяти , а стрелки показывают отображение стра­ ницы . В иртуальные адреса Верхняя nамять ; Процесс Ниж няя память Логические адреса Процесс Рис. 8.3. Типы адресов в Li11ux ,. ...-.. -... -... --.. --.... -................ --.. --..... -.......... -..... ·... --.. --.·tlll .
....................... n..,пux Ящю (,i1шх 8.2. Методы управления подсистемой памяти 8.2.1. Подкачка и невытесняемая память Для работы с памятью в Linux (как и в других UNIХ-подобных системах) ха­ рактерно такое явление как "страничный обмен" (paging). Оно заключается в том, что ядро выделяет процессам столько памяти, сколько им необходимо. В том смысле , чтобы ее (памяти) всегда хватало. Это достигается за счет расширения физической памяти за счет виртуальной, т. е. "подкачки". По­ скольку выполнение процессов должно происходить в реальной физической памяти, то ядро постоянно перемещает страницы памяти процессов между физической и виртуальной памятью. Забегая вперед, следует отметить, что в виртуальной памяти хранятся "неактивные" страницы, которые не задей­ ствованы процессом в данный момент, но необходимые ему для полноцен­ ной работы впоследствии. С файловой памятью все просто: если данные в ней не менялись, то для ее вытеснения делать особо ничего не нужно - просто перетираешь, а затем всегда можно восстановить из файловой системы. С анонимной памятью такой трюк не работает: ей не соответствует никакой файл , поэтому чтобы данные не пропали безвозвратно., их нужно положить куда-то еще. Для этого можно использовать так называемый "swар"-раздел или файл. Можно, но на практике не нужно. Если swap выключен, то ано­ нимная память становится невытесняемой, что делает время обращения к ней предсказуемым. Может показаться минусом выключенного swap, что, например, если у при­ ложения утекает память, то оно будет гарантированно зря держать физиче­ скую память (утекшая не сможет быть вытеснена). Но на подобные вещи скорее стоит смотреть с той точки зрения, что это наоборот поможет раньше обнаружить и устранить ошибку. 8.2.2. Системный вызов mlockO По умолчанию вся файловая память является вытесняемой, но ядро .. Linux , предоставляет возможность запрещать ее вытеснение с точностью не только до файлов , но и до страниц внутри файла . . ---- --- ----- -- -- --- ................ -.... --·· ... ---- ....... ···-. ------. -----. ___
1J 1aiш Х. У11равJ1с1tис 11а 1шп ыо n.1nux .. ............ _·_.. Для этого используется системный вызов памяти, полученной с помощью mlock() mmap . Если на области виртуальной спускаться до уровня систем­ ных вызовов не хочется, рекомендую посмотреть в сторону консольной ути­ литы vmtouch, которая делает ровно то же самое , но снаружи относительно приложения. Несколько примеров, когда это может быть целесообразно : • У приложения большой исполняемый файл с большим количеством вет­ влений, некоторые из которых срабатывают редко, но регулярно. Такого стоит избегать и по другим причинам , но если иначе никак , то, чтобы не ждать лишнего на этих редких ветках кода, можно запретить им вытес­ няться. • Индексы в базах данных часто физически представляют собой именно файл, с которым работают через mmap, а mlock нужен чтобы минимизи­ ровать задержки и число операций ввода-вывода на и без того нагружен­ ном диске(-ах). • Приложение использует какой-то статический словарь, например, с соот­ ветствием подсетей IР-адресов и стран, к которым они относятся. Вдвой­ не актуально, если на одном сервере запущено несколько процессов , ра­ ботающих с этим словарем. 8.2.3. ООМ killer Перестаравшись с невытесняемой памятью , нетрудно загнать операцион­ ную систему в ситуацию, когда физическая память кончилась , а вытеснять нич;его нельзя. Безысходной она выглядит лишь на первый взгляд : вместо вытеснения память можно освободить. Происходит это достаточно радикальными методами: послуживший назва­ нием данного раздела механизм выбирает по определенному алгоритму про­ цесс, которым наиболее целесообразно в текущий момент пожертвовать - с остановкой пр_оцесса -освобождается использовавшаяся им память, которую можно перераспределить между выжившими. Основной критерий для выбо­ ра: текущее потребление физической памяти и других ресурсов, плюс есть возможность вмешаться и вручную пометить процессы как более или менее ценные, а также вовсе исключить из рассмотрения. Если отключить ООМ • ... . -- -- -- .. -- ...... -.... --- .... ........ ................ --... --...... --.. --- . -- -.. . . .
Я ! tро l , i11ю: ·······················a.nux killer полностью, то системе, в случае полного де фицита, ничего не останет­ ся, как перезагрузиться. 8.2.4. cgroups По умолчанию все пользовательские процессы наравне претендуют на поч­ ти всю физически доступную память в рамках одного сервера. Это поведе­ ние редко является приемлемым. Даже если сервер условно-однозадачный, например, т<_шько отдает статические файлы по НТТР с помощью всегда есть какие-то служебные процессы вроде syslog nginx, или какой-то вре­ менной команды , запущенной человеком. Если же на сервере одновременно работает несколько production -пpoцeccoв, например, популярный вариант подсадить к веб-серверу memcached, - крайне желательно чтобы они не могли начать "воевать" друг с другом за память в случае ее дефицита. Для изоляции важных процессов в современных ядрах существует механизм cgroups, с его помощью можно разделить проu;ессы на логические группы и статически сконфигурировать для каждой из групп сколько физической памяти может быть ей выделено. После чего для каждой группы создается своя почти независимая подсистема памяти, со своим отслеживанием вы­ теснения, ООМ Механизм killer и cgroups прочими радостями. намного обширнее, чем просто контроль за потреблени­ ем памяти. С его помощью можно распределять вычислительные ресурсы, "прибивать" группы к ядрам процессора, ограничивать ввод-вывод и многое другое . Сами группы могут быть организованы в иерархию и вообще на ос ­ нове cgroups работают многие системы "легкой" виртуализации и нынче модные Dосkеr-контейнеры . . Но, на мой взгляд , именно контроль за потреблением памяти - самый необходимый минимум, который определенно стоит настроить, осталь!iое уже по желанию/необходимости. 8.2.5.NUMA В многопроцессорных системах не вся память одинакова. Если на материн­ ской плате предусмотрено N процессоров (например, 2 или все слоты для оперативной памяти физически разделены на 4), то обычно N групп так, что • ............................................................... , ............ . .... . . .
1J 1ава n.1nux ................. . Х . Y11p:111лt•1111t• ш1м)111,ю каждая из них располагается ближе к соответствующему ей процессору такую схему называют - NUMA 4 . Таким образом, каждый процессор может обращаться к определенной 1/N части физической памяти быстрее (примерно раза в полтора), чем к остав­ шимся Ядро (N-1 )/N. Linux самостоятельно умеет это все определять и по умолчанию достаточно разумным образом учитывать при планировании выполнения процессоров и выделении им памяти. Посмотреть, как это все выглядит и подкорректировать можно с помощью утилиты системных вызовов, в частности 8.3. numactl и ряда get_ mempolicy/set_mempolicy. Механизм распределения доступных LRU Ядро старается управлять памятью таким образом, чтобы недавно исполь­ зуемые процессом страницы находились в физической памяти. И в свою очередь , "неактивные" или редко использу,емые страницы перемещаются и хранятся в виртуальной памяти в области "подкачки". Такой механизм рас­ пределения памяти называется LRU (least recently used) - замещение наиболее редко используемых страниц. Вторым важнейшим аспектом в работе памяти является использование кэш­ буфера страниц. Это вытекает из работы алгоритма LRU, который доволь­ но сложен в своей реализации. Поскольку следить за всеми обращениями к страницам - это в некоторых случаях, довольно ощутимые потери в про­ изводительности системы. Использование же страничного кэш-буфера куда проще в своей реализации при тех же самых результатах. К тому же данный подход имеет огромный модернизационный потенциал (в отличие от LRU) и алгоритмы анализа содержимого кэш-буфера (для определения, какие стра­ ницы должны рыть перемещены из виртуальной памяти) постоянно совер­ шенствуются. Что заметно сказывается на производительности и эффектив­ ности управления памятью. Когда процессу не хватает памяти , то ядро начинает искать "занятые" стра­ ницы, которые можно использовать для "голодающего" процесса. Обычно такими страницами являются те, что давно не были использованы. Ядро - проверяет их на предмет модификации каким-либо процессом. Для этого существуют определенные признаки, при последнем обращении и если из- f Non-Uniform Memory Access, неравн омерны й д ост уп к памяти ........ -- ........... ---- --- ... -.................... -· ............ ... -... .... ·····
Я 1 tро 1-inux ....................... rl.inux менения были , то такие страницы помечаются ядром как "грязные" (dirty), т. е . такие , которые еще нужны процессам. Для повторного использования памяти такие страницы сначала обязательно переносятся в виртуальную па­ мять. Все же остальные страницы являются "чистыми". И поэтому ядро их использует для предоставления другим или "голодающим" процессам. Когда происходит обращение к страницам памяти, которые некоторое или долгое время не использовались , т. е. к "неактивным" страницам, ядро вы­ полняет с ними несколько важных задач: • Возвращает ссылки на эти страницы в соответствующей таблице страниц; • Сбрасывает в нулевое значение время "неиспользования" этих страниц; • Помечает эти страницы как "активные" . Со страницами, находящимися в виртуальной памяти не все так однозначно. Дело в том , что для того, чтобы "активизировать" такие страницы, они долж­ ны быть предварительно прочитаны с диска. Системное ядро комплектуется специализированными модулями, которые содержат алгоритмы и даже целые технологии. Посредством данных тех­ нологий система доволqно эффективно "предсказывает", сколько может по­ требоваться памяти при разной степени активности и загруженности про­ цессов . Данные алгоритмы имеют своей целью обеспечение процессов свободной памятью с максимальной эффективностью, т.е. так, чтобы про­ цессам как можно реже приходилось простаивать в "ожидании" выгрузки очередной страницы в свободную память. Таким образом , наблюдая за состоянием страничного обмена во время рабочей нагрузки системы, можно делать выводы о том, нужна ли ей дополнительная память. Если страничный обмен интенсивный - то однозначно следует установить дополнительные модули ОЗУ. Если же происходит так, что процессам не хватает ни реальной физической, ни виртуальной памяти, т.е. когда память полностью исчерпана, система на­ чинает завершать (а точнее уничтожать) целые процессы. Либо запрещает создание новых . Конечно, в этом случае в первую очередь уничтожаются наиболее "безболезненные" для системы процессы. Однако в таких случая:х: даже "на глаз" и по собственным ощущениям видно, что она большую часть времени тратит на управление памятью, а не на выполнение рабочих задач . • 1D ................................................................................. .
1~ ,ава R. n..inux _________________ _ В Linux У11равле11ие 11амs11 ыо можно настроить параметр, который задает, насколько быстро ядро должно "отбирать" страницы памяти у процессов, которым они менее нуж­ ны - для процессов , которым они на данный момент необходимы . Этот па­ раметр содержится в файле 60. /proc/sys/vm/swappiness и по умолчанию равен Если задать его меньшим значением (например , О) , то ядро будет заби­ рать страницы процесса в самую последнюю очередь, используя ~место это­ го любые другие варианты. Если это значение в пределах между 60 и 100, то страницы будут отбираться у процессов с более высокой вероятность~ . Вариант с изменением данного параметра на с.амом деле говорит о том, что необходимо либо снизить нагрузку на систему, адаптировав ее для других, менее производительных задач, либо увеличить объем ОЗУ. 8.4. Дополнительные памятью в Linux Управление памятью в Linux сведения об управлении представляет собой сложную систему, которая развивалась с годами и включала все больше и больше функций для под­ держки различных систем , от микроконтролл;еров без ММU до . суперком­ пьютеров. Управление памятью для систем без ММU называется nommu, и оно определенно заслуживает отдельной книги, которая , надеемся , в конеч­ ном итоге будет написана. Тем не менее, хотя некоторые концепции одинако­ вы , здесь мы предполагаем, что MMU доступен, и CPU может преобразовать виртуальный адрес в физический адрес . 8.4.1. Снова о виртуальной памяти Физическая память является ограниченным ресурсом , и д аже для систем, поддерживающих горячее подключение памяти, существует жесткое ограни­ чение на объем устанавливаемой памяти . Физическая память не обязательно непрерывна - она может быть доступна как набор отдельных диапазонов адресов. Кроме того , разные архитектуры CPU и даже разные реализации одной и той же архитектуры имеют разные представления о том, как опреде­ ляются эти диапазоны адресов.
И 1 1ро l,i1111x ................... .... n.1nux Все это делает непосредственную работу с физической памятью довольно сложной, и чтобы избежать этой сложности, была разработана концепция виртуальной памяти. Виртуальная память абстрагирует детали физической памяти от приклад­ ного программного обеспечения, позволяет хранить в физической памяти только необходимую информацию (подкачка по запросу) и обеспечивает ме­ ханизм защиты и контролируемого обмена данными между процессами. С виртуальной памятью каждый доступ к памяти использует виртуальный адрес. Когда CPU декодирует инструкцию, которая читает (или записывает) из (или в) системную память , он транслирует виртуальный адрес, закоди­ рованный в этой инструкции , в физический адрес, который может понять контроллер памяти. Физическая системная память разделена на страничные фреймы или страни­ цы. Размер каждой страницы зависит от архитектуры . Некоторые архитек­ туры позволяют выбирать размер страницы из нескольких поддерживаемых значений - этот выбор выполняется во время сборки ядра путем установки соответствующей опции конфигурации ядра. Каждая страница физической памяти может отображаться как одна или несколько виртуальных страниц. Эти сопоставления описываются табли­ цами страниц, позволяющими выполнять преобразование виртуального адреса, используемого программами , в адрес физической памяти. Таблицы страниц организованы иерархически. Таблицы на самом низком уровне иерархии содержат физические адреса фактических страниц, используемых программным обеспечением. Табли­ цы более высоких уровней содержат физические адреса страниц, принад­ лежащих более низким уровням. Указатель на таблицу страниц верхнего уровня находится в регистре. Когда процессор выполняет трансляцию адресов, он использует этот регистр для доступа к таблице страниц верх­ него уровня. Старшие биты виртуального адреса используются для ин­ дексации записи в таблице страниц верхнего уровня . Эта запись затем ис­ пользуется для доступа к следующему уровню в иерархии со следующими битами виртуального адреса в качестве индекса к таблице страниц этого уровня. Младшие биты виртуального адреса определяют смещение внутри фактической страницы. • ID- ----. --------------. ---.. ---. ---. --. ---"-. -"--"-"-. --.. ----. -. --. --. --". ---------.
1J1a11a n.1nux ................. . 8.4.2. Х. У111э,11шс1111с ш1~н111,ю Большие страницы Преобразование адресов требует нескольких обращений к памяти , а обра­ щения к памяти медленны относительно скорости проце ссора. Чтобы не тратить драгоценные циклы процессора на преобразование адресов , про­ цессоры поддерживают кэш таких преобразований , наз ывае м ый буфером преобразования (или Translation Lookaside Buffer, TLB) . Обычно TLB явля­ ется довольно дефицитным ресурсом , и приложения с больши м рабочим на­ бором памяти будут испытывать снижение производительности из-за про­ махов TLB. Многие современные архитектуры CPU позволяют отображать страницы памяти непосредственно на более высокие уровн и в табли це страниц. Например , на х86 можно отображать страницы р азмер ом 2М и даже пользуя записи в таблицах страниц второго и третьего уровня . В страницы называются большими (huge pages). TLB, ниц значительно снижает нагрузку на TLB lG, ис­ Linux такие Использо вание больших стра­ повыш ает частоту попаданий и, таким образом, повышает общую произ водительн ость си стемы. В ОС Linux есть два механизма, которые позвол яют сопо ставлять физи­ ческую память с большими страницами. Первый HugeTLB, - это файловая система или hugetlЬfs. Это псевдо файловая система, которая использует оперативную память в качестве резервного хранилища. Для файлов, создан­ ных в этой файловой системе, данные находятся в памяти и отображаются с использованием больших страниц. Другой , более современный механизм, позволя ющий использовать боль­ шие страницы , называется Transparent HugePages или ТНР. В отличие от hugetlЬfs, который требует от пользователей и/или системных администра­ торов настройки того , какие части системной п амяти должны и могут быть отображены большими страницами, ТНР управляет такими сопоставления­ ми прозрачно для пользователя и , следовател ьно , для имени . 8.4.3. Зоны Зачастую оборудование накладывает ограничения на доступ к различным диапазонам физической памяти . В некоторых случаях устройства не могут выполнять прямой доступ к памяти • (DMA, Direct Memory Access) для всей .. . . ... . ...... ... .. . . . . .. .. . . . .. .. . . . . . ... . . . . . . ........ ... . ...... ... . ..... .. ... . --
Ядро Linux ........... . .......... n..inux адресуемой памяти. В других случаях размер физической памяти превыша­ ет максимальный адресуемый размер виртуальной памяти, и для доступа к частям памяти требуются специальные действия. ОС Linux группирует страницы памяти в зоны в соответствии с их возмож­ ным использованием. Например, ZONE_ DMA будет содержать память, кото­ DMA, ZONE_HIGHMEM будет рая может использоваться устройствами для содержать память, которая не отображается постоянно в адресное простран­ ство ядра, а ZONE_NORМAL будет содержать страницы с обычной адреса­ цией. Фактическое расположение зон памяти зависит от аппаратного обеспечения, поскольку не все архитектуры определяют все зоны, а требования к прямому доступу к памяти различаются для разных платформ. 8.4.4. Узлы Многие многопроцессорные машины являются системами Uniform Memory Access). NUMA (Non- В таких системах память организована в банки, ко­ торые имеют разную латентность доступа в зависимости от "удаленности" от процессора. Каждый банк называется узлом, и для каждого узла Linux создает независимую подсистему управления памятью. У узла есть свой на­ бор зон, списки свободных и используемых страниц и различные счетчики статистики . 8.4.5. Кэш страницы Физическая память энергозависима, и обычным случаем получения данных в память является их чтение из файлов. Всякий раз , когда файл читается, данные помещаются в кэш страниц во избежание "дорогостоящего" (по фак­ ту - длительного) доступа к диску при последующих чтениях. Точно так же, как когда кто-то записывает в файл, данные помещаются в кэш страниц и, в конечном итоге , попадают на резервно е запоминающее устройство. Запи­ санные страницы помечаются как грязные, и когда ядро решает Linux повторно использовать их для других целей, оно обязательно синхронизиру­ ет содержимое файла на устройстве с обновленными данными . . . . . .. -- . . --.. ---- --. --- -- --- ---- -- -- -. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - . . . · . · . . . . • -. . . .
1 1:tll:t t.\.1nux ................. . 8.4.6. Х Y11Jlallclt' Jlllt' ШIMil 11,Ю Анонимная память Анонимная память или анонимные сопоставления представляют собой па­ мять, которая не поддерживается файловой системой. Такие отображения создаются неявно для стека и программ или явными вызовами системного вызова mmap(). Обычно анонимные сопоставления определяют только обла­ сти виртуальной памяти , к которым программе разрешен доступ . Доступ для чтения приведет к созданию записи в таблице страниц , которая ссылается на специальную физическую страницу, заполненную нулями. Когда программа выполняет ·запись , для хранения записанных данных выделяется обычная физическая страница. Страница будет помечена как грязная , и если ядро ре­ шит перепрофилировать ее , грязная страница будет заменена. 8.4.7. Освобождение На протяжении всего жизненного цикла системы физическая страница мо­ жет использоваться для хранения различных типов данных . Это могут быть внутренние структуры данных ядра, буферы с поддержкой DMA для исполь­ зования драйверами устройств, данные, считанные из файловой системы, память, выделенная процессами пользовательского пространства и т. д. В зависимости от использования страницы управление памятью Linux об­ рабатывает ее по-разному. Страницы, которые могут быть освобождены в любое время либо. потому, что они кэшируют данные, доступные в другом месте, например, на жестком диске, либо потому, что их можно выгрузить, опять же, на жесткий диск, называются восстанавливаемыми. Наиболее за­ метными категориями восстанавливаемых страниц являются кэш страниц и анонимная память. В большинстве случаев страницы, содержащие внутренние данные ядра и используемые в качестве буферов DМА, не могут быть переназначены , и они остаются закрепленными до тех пор, пока их не освободит пользова­ тель. Такие страницы называются невосстановимыми . Однако при опреде­ ленных обстоятельствах могут быть освобождены даже страницы, занятые структурами данных ядра. Например, кэши метаданных файловой системы в памяти могут быть повторно прочитаны с устройства хранения и, следо­ - вательно , их можно удалить из основной памяти, когда система испытывает , нехватку памяти. _ ..................... ....... " " ... _ " ". - .. .. " "" ... " " .. ". ". "" ...... ". " .............
и ,, .,ю l ,illll\ ...................... n.1nux Процесс освобождения восстанавливаемых страниц физической памяти и их перепрофилирования называется освобождением ОС Linux (reclaim). может освобождать страницы либо асинхронно, либо синхрон­ но, в зависимости от состояния системы. Когда система не загружена, большая часть памяти свободна, и запросы на выделение будут немед­ ленно удовлетворены за счет наличия свободных страниц. По мере уве ­ личения нагрузки количество свободных страниц уменьшается, и когда оно достигает определенного порога (нижний водяной знак), запрос на выделение пробуждает демон kswapd. Он будет асинхронно сканировать страницы памяти и либо просто освобождать их, если данные, которые они содержат, доступны в другом месте, либо вытеснять их на резервное устройство хранения (помните эти грязные страницы?). По мере того, как использование памяти увеличивается еще больше и достигает дру­ гого порога - минимального водяного знака - выделение инициирует прямое восстановление. В этом случае выделение останавливается до тех пор, пока не будет высвобождено достаточное количество страниц памя­ ти для удовлетворения запроса. 8.4.8. Уплотнение (сжатие) По мере работы системы, задачи выделяют и освобождают память, и она становится фрагментированной. Хотя с помощью виртуальной памяти мож­ но представить разрозненные физические страницы как виртуально непре­ рывный диапазон, иногда необходимо выделить большие, физически непре­ рывные области памяти. Такая необходимость может возникнуть, например, когда драйверу устройства требуется большой буфер для DMA, или когда ТНР выделяет большую страницу. Сжатие памяти решает проблему фраг­ ментации. Этот механизм перемещает занятые страницы из нижней части зоны памяти в свободные страницы в верхней части зоны. По завершении сканирования с уплотнением свободные страницы группируются вместе в начале зоны, и становится возможным выделение больших физически смеж­ ных областей. Как и операция kcompactd или • reclaim, сжатие может происходить асинхронно в демоне синхронно в результате запроса на выделение памяти. • ············ ······· ·······························································
1 т111а Х . Yщ)a11J1t·1111t• ш1мs111.ю n.1nux .. ..... .......... . 8.5. Большие страницы . Бол ее подробн о 8.5.1. Общая информация Как уже отмечалось ранее, ядро (hugetlb ). Linux поддерживает большие страницы Эта поддержка построена на основе поддержки нескольких раз­ меров страницы , которая обеспечивается большинством современных архи­ тектур. Например, процессоры х86 обычно поддерживают размеры страниц 4К и 2М (lG, если поддерживается архитектурой), архитектура держивает несколько размеров страниц: 4К, 8К, 64К, 256К, 256М, а ррс64 поддерживает 4К и TLB - lM, ia64 под­ 4М, 16М, 1бМ. это кэш преобразований виртуального в физическое. Как правило, на подобные преобразования тратится достаточно ресурсов процессора, поэтому кэш просто необходим. Операционные системы пытаются наилуч­ шим образом использовать ограниченное количество ресурсов TLB. Данная оптимизация становится все более важной сейчас, поскольку все больше и больше физической памяти становится все более доступнее. Пользователи могут использовать поддержку больших страниц в ядре mmap или SYSV (shmget, shmat). используя системный вызов общей памятью Linux, стандартные системные вызовы с Сначала необходимо собрать ядро Linux с параметрами конфигурации CONFIG_HUGETLBFS (находится в разделе "File systems") и CONFIG HUGETLB_PAGE (выбирается автоматически при выборе CONFIG HUGETLBFS). Файл /proc/meminfo постоянных страниц предоставляет информацию об общем количестве hugetlb в пуле больших страниц ядра. Он также отобра­ жает размер большой страницы по умолчанию и информацию о количестве свободных , зарез ервированных и избыточных больших страниц в пуле боль­ ших страниц размера по умолчанию. Указание размера большой страницы необходимо дл я создания правильного выравнивания и размера аргументов для системных вызовов, которые отображают области больших страниц. Вывод cat /proc/meminfo будет примерно следующим : HugePages_Tot a l : uuu HugePages_Free : vvv . ugePages_Rsvd : www ..................... . .... . .... -.................... -- -.................. -....... --
Ищ111 l ,i1111x ...................... t't1nux HugePages_Surp : Hugepagesize : Hugetlb : ххх kB zzz kB ууу Где: • HugePages_Total - это размер пула больших страниц. это количество больших страниц в пуле, которые еще • HugePages_Free не выделены . • HugePage·s_Rsvd - является сокращением от "зарезервировано" и пред­ ставляет собой количество больших страниц, для которых было принято обязательство о выделении из пула, но еще не бьшо выделено. Зарезерви­ рованные большие страницы гарантируют, что приложение сможет вы­ делить большую страницу из пула больших страниц в случае сбоя. • HugePages_ Surp - является сокращением от "избыточный" и представля­ ет собой количество больших страниц в пуле, превышающее значение в /proc/sys/vm/nr_ hugepages. Максимальное количество избыточных боль­ ших страниц контролируется /proc/sys/vm/nr_ overcommit_hugepages. Если включена функция освобождения неиспользуемых страниц vmemmap, связанных с каждой страницей hugetlb, количество избыточных больших страниц может временно превышать максимальное количество избыточ­ ных больших страниц, когда система испытывает нехватку памяти. • Hugepagesize - это размер большой страницы по умолчанию (в килобай­ тах). • Hugetlb- общий объем памяти (в килобайтах), потребляемый большими страницами всех размеров. Если используются большие страницы разно­ го размера, это число превысит HugePages_Total * Hugepagesize. Чтобы /sys/kemeUmm/ получить более подробную информацию, обратитесь к hugepages. Файл /proc/filesystems также должен показывать файловую систему тиnа "huget\Ьfs", сконфигурированную в ядре. Файл /proc/sys/vm/nr_hugepages указы вает текущее количество "постоян­ ных" больших страниц в пуле больших страниц ядра. "Постоянные" боль­ шие страницы будут возвращены в пул страниц при задаче освобождения памяти. Пользователь с привилегиями root может динамически выделять • . .... -- ........................................ ... ········ -·. ---- .. ····-···- ····-·· ·
1 · 1а11а n..inux ................. . :,,;_ Y11paB.lt'llllt' 11:1\J)J I J,IO больше или освобождать некоторые постоянные большие страницы, увели­ чивая или уменьшая значение nr_hugepages. Страницы, которые используются как большие (huge ), зарезервировавы вну­ три ядра и не могут использоваться для других целей . Большие страницы не могут быть выгружены из-за нехватки памяти. Как только несколько больших страниц были предварительно выделены в пул больших страниц ядра, пользователь с соответствующими правами мо­ жет использовать либо системный вызов mmap(), либо системные вызовы с общей памятью для использования больших страниц . Администратор может выделить постоянные hugе-страницы, используя параметр ядра "hugepages=N", где "N" = количество запрошенных hugе­ страниц. Это самый надежный метод выделения больших страниц, так как память еще не стала фрагментированной . • Некоторые платформы поддерживают несколько больших размеров страниц. Чтобы выделить большие страницы определенного размера, перед параме­ трами команды загрузки больших страниц необходимо указать параметр вы­ бора размера большой страницы "hugepagesz=<paзмep>". <размер> должен быть указан в байтах с необязательным суффиксом масштаба [kКmМgG]. Размер hugе-страницы по умолчанию можно выбрать с помощью параметра ядра "default_hugepagesz=<paзмep>" . Семантика параметра командной строки загрузки Hugetlb: • hugepagesz Указывает размер hugе-страницы . Используется в сочетании с параметром hugepages для предварительного выделения ряда болъшliх страниц указан­ ного размера. Следовательно , параметры ядра hugepagesz и hugepage указы­ ваются парами: hugepages z=2 M hugepages=512 Параметр hugepagesz можно указать только один раз в командной строке. До­ пустимый размер таких страниц зависит от архитектуры. ·················································································· -
Я .' tро l,inux ........... __ ·_........ n.inux • hugepages Укажите количество больших страниц для предварительного выделения. Обычно он указывается после параметра hugepagesz или default_hugepagesz. hugepages является первым или единственным параметром ко­ строки hugetlb, он неявно указывает количество больших страниц с Однако если мандной размером по умолчанию, которые будут выделены. Если количество страниц размера по умолчанию указано неявно, оно не мо­ жет быть перезаписано парой параметров hugepagesz,hugepages для размера по умолчанию. • default_ hugepagesz• Задает размер по умолчанию для больших страниц. Данный параметр мож­ но указать только один раз в командной строке. За дополнительно следовать параметр hugepages, default_hugepagesz может чтобы предварительно вы­ делить определенное количество больших страниц размера по умолчанию. Количество больших страниц размера по умолчанию для предварительного выделения также может быть неявно указано, как указано в разделе о боль­ ших страницах ранее . Следовательно , на архитектуре с размером большой страницы в 2 Мб конфигурация: hugepages= 256 default_hugepagesz=2M hugepages=256 hugepages=256 default hugepagesz=2M приведет к выделению 256 больших страниц по 2М. Допустимый размер большой страницы по умолчанию зависит от архитектуры. • hugetlbJree _ vmemmap Когда опция ядра CONFIG HUGETLB PAGE OPТIMIZE VMEMMAP установлена (она устанавливается при компиляции ядра), это включает оп­ тимизацию HugeTLB Vmemmap (HVO). • I D---.--------------------.---.. -... ----.--------.---.. ---.. -.. --.. ----------------.
l ".11ана Х. У11рав. н.• 111н• 1ш,1я 11,ю t\.inux ................. . Когда поддерживаются несколько больших страниц, фа.йл hugepages указывает текущее количество предварительно /proc/sys/vm/nr_ выделенных бо1;1ь­ ших страниц размера по умолчанию . Таким образом, можно использовать следующую команду для динамического выделения/освобождения постоян­ ных больших страниц по умолчанию: ech o 2 0 > / pr o c / sys / vm / nr hugepages Эта команда попытается установить количество больших страниц с разме­ ром по умолчанию в пуле страниц до 20, выделяя или освобождая большие страницы по мере необходимости. На платформе NUMA ядро попытается распределить пул больших страниц по всему набору разрешенных узлов, указанному в политике памяти задачи, изменяющей nr_ hugepages . NUMA Разрешенные узлы с недостаточной доступной непрерывной памятью для большой страницы будут автомати-. чески пропущены при выделении постоянных больших страниц. Успех выделения больших страниц зависит от объема физически непрерыв­ ной памяти, которая присутствует в системе во время попытки выделения. Если ядро не может выделить большие страницы для некоторых узлов в системе NUMA, оно попытается компенсировать разницу, выделив допол­ нительные страницы на других узлах с достаточным количеством доступной непрерывной памяти , если таковая имеется. Системные администраторы могут захотеть поместить эту команду в один из локальных файлов инициализации rc. Это позволит ядру выделять боль­ шие страницы в начале процесса загрузки, когда вероятность получения фи­ зических смежных страниц все еще очень высока. Администраторы могут проверить количество фактически выделенных больших страниц, проверив файл sysctl или meminfo. Чтобы проверить распределение больших страниц NUMA, используйте: по узлам в системе c at / sys / devices / syst e m/ node / node* / memin f o I f g rep Huge Файл /proc/sys/vm/nr_ overcommit_hugepages указывает, насколько большим может стать пул больших страниц, если приложения запрашивают больше страниц, чем /proc/sys/vm/nr_ hugepages. Запись любого ненулевого значения в этот файл указывает на то, что подсистеме • hugetlb разрешено пытаться .-----------.---\. -------. ----.---.. -------. -------------.--... -.----------... -----tD •
Я , tро l,i1111x ...................... t81..1nux получить это количество "избыточных" больших страниц из обычного пула страниц ядра, если постоянный пул больших страниц исчерпан. Когда эти лишние большие страницы становятся неиспользуемыми, они возвращают­ ся в обычный пул страниц ядра, При увеличении размера пула больших страниц с помощью nr_hugepages любые существующие избыточные страницы сначала будут преобразованы в постоянные большие страницы , Затем, если это необходимо и возможно, будут выделены дополнительные большие страницы, чтобы заполнить но­ вый постоянный размер пула больших страниц, Администратор может уменьшить пул постоянных больших страниц. уста­ новив sysctl nr_ hugepages в меньшее значение , Ядро попытается сбаланси­ ровать освобождение больших страниц на всех узлах в политике памяти за­ дачи, изм~няющей nr_hugepages, Любые свободные большие страницы на выбранных узлах будут возвращены в обычный пул страниц ядра, Внимание! Сокращение постоянного пула больших страниц с по­ мощью nr_hugepages так, что он станет меньше, чем количество используемых больших страниц, приведет к преобразованию баланса используемых больших страниц в избыточные большие страницы. Это произойдет, даже если количество избыточных страниц превыс'ит значение overcommit. Пока выполняется это условие, то есть пока nr_hugepages+nr_overcommit_hugepages не будет увеличено в достаточной степени или лишние большие страницы не выйдут из использования и не будут освобождены, система больше не разрешит выделять дополнительные боль­ шие страницы , Благодаря поддержке нескольких пулов больших страниц во время выпол­ нения большая часть интерфейса пользовательского пространства больших страниц в сы /proc /proc/sys/vm дублируется в sysfs, Обсуждавшиеся выше интерфей­ были сохранены для обратной совместимости, Корневой каталог управления большими страницами в sysfs: /sys/ kern el/mm/hugepages Для каждого размера большой страницы, поддерживаемого работающим ядром, будет существовать подкаталог в форме: - • ···· -· ............ ----- ----- --- .... -· .. ·-·-. - . ---· ·- -··-·-·. --- . -- -...... .. .. .. .. . •
1 t\.1nux ........... ...... . 1а11а Х . Yщt,111.1t•1111t• ШI\HI 11,ю hugepages-${size }kB Внутри каждого из этих каталогов будет существовать набор файлов, содер­ жащихся в /proc. Кроме того, могут существовать два дополнительных ин­ терфейса для понижения уровня больших страниц: demote demote size n r_hugepages n r hugepa~es_mempolicy n r_overcommit_hugepages free hugepages resv_hugepages surp lu s _hugepages Интерфейсы понижения уровня предоставляют возможность разбить боль­ шую страницу на более мелкие большие страницы. Например, архитектура х86 поддерживает большие страницы размером ницу размером 1 ГБ можно разделить на 512 1 ГБ и 2 МБ. Большую стра­ больших страниц по 2 МБ. По­ нижение интерфейсов недоступно для самых маленьких больших страниц. Интерфейсы понижения приведены ниже: • demote_size - размер пониженных страниц. Когда уровень страницы бу­ дет понижен, будет создано соответствующее количество больших стра­ ниц demote_size. По умолчанию для параметра demote_size установлен следующий меньший размер большой страницы. Если существует несколько меньших больших размеров страниц, для параметра size demote_ можно установить любой из этих меньших размеров. Допускаются только те размеры больших страниц, которые меньше текущего рцзмера больших страниц. • demote - используется для понижения ряда больших страниц. Пользо­ ватель с привилегиями root может писать в этот файл . Возможно, будет невозможно понизить запрошенное количество больших страниц. Чтобы определить, сколько страниц было фактически понижено , сравните зна­ чение фейс • nr_ hugepages до и после записи в интерфейс demote поддерживает только запись . понижения. Интер­ ·--·--···-·····--------·-···········-·················-··--···--··--··--···--···-· -
}1 11ю l .i1111, 8.5.2. ....................... f't.1nux Взаимодействие политики памяти задач с выделением/ освобождением больших страниц Независимо от того, выделяются и освобождаются ли больших страницы через интерфейс /proc или интерфейс /sysfs с использованием атрибута nr_ hugepages_ mempolicy, узлы NUМA, из которых выделяются или осво­ бождаются большие страницы , контролируются политикой памяти NUMA задачи, которая изменяет sysctl или атрибут nr_ hugepages _ mempolicy. Когда используется атрибут nr_ hugepages, mempolicy игнорируется . Рекомендуемый метод для выделения или освобождения больших страниц в/из пула больших страниц ядра, используя приведенный выше пример nr_hugepages: numactl -- interleave <список узлов> echo 20 \ >/proc/sys/vm/nr_hugepages_mempolicy или , более кратко: numactl - m <список - узлов> echo 20 >/proc / sys /vm/ nr_hugepages_mempolicy Это выделит или освободит abs(20 - nr_hugepages) для узлов , указанных в <список-узлов >, или из них , в зависимости от того, изначально ли количе­ ство постоянных больших страниц меньше или больше 20 соответственно. Большие страницы не будут выделены или освобождены ни на одном узле, не включенном в указанный <список-узл ов>. При настройке постоянного кол ичества больших страниц с помощью nr_hug_epages_mempolicy можно использовать л юбой режим политики - привязку, предпочтительный, л ок альный или черед ование . памя­ ти 8.5.3. Атрибуты больших страниц для каждого узла Подмножество страницами в содержимого sysfs, корневого каталога управления большими описанного выше , будет репл ицировано под каждым системным устройством каждого узл а NUMA с памятью в: • . . ....................... ............................................................ •
1 1 1а11а n.1nux ................. . Х Ущ1а11.' 1t•11ш• 11а~ш 11.111 /sys/devices/system/node/node[0 - 9]*/hugepages/ В этом каталоге подкаталог для каждого поддерживаемого большого разме­ ра стра!:Jицы содержит следующие файлы атрибутов: nr_hugepages free_hugepages surplus hugepages Файлы атрибутов free _ * и surplus_ * доступны только для чтения. Они воз­ вращают количество свободных и избыточных больших страниц соответ­ ственно на родительском узле. Атрибут nr_ hugepages возвращает общее количество больших страниц на указанном узле. Когда этот атрибут записан, количество постоянных боль­ ших страниц на родительском узле будет скорректировано до указанного значения если существует до статочно ресурсов, независимо от ограничений памяти задачи или набора процессоров. Обратите внимание, что количество избыточных и резервных страниц оста­ ется глобальными величинами, поскольку мы не знаем до момента сбоя, ког­ да применяется мемполитика сбойной задачи, с какого. узла будет предпри- нята попытка выделения большой страницы . 8.5.4. ' Использование больших страниц Если пользовательские приложения будут запрашивать большие страницы с помощью системного вызова mmap(), то нужно, чтобы системный админи­ стратор смонтировал файловую систему типа hugetlbfs: mount - t hugetlbfs \ - о uid=<val ue> , gid=<value>, mode=<value> , pagesize=<value> , size=<value>, \ min_size=<value> , nr_inodes=<value> none /mnt/huge • ·----------------------------··-·····-··--···----------·-·--·----··----- ---------- -
И , 11ю lai1111, ...................... rl.1nux Эта команда монтирует (псевдо) файловую систему типа /mnt/huge. Любой файл, созданный в /mnt/huge, hugetlbfs в каталог использует большие страни­ цы. Параметры uid и gid задают владельца и группу корня файловой системы . По умолчанию берутся Опция mode &01777. Это uid и gid текущего процесса. устанавливает режим корня файловой системы на значение значение задается в восьмеричном формате. По умолчанию выбрано значение 0755. Если платформа поддерживает несколько размеров больших страниц, па­ раметр pagesize можно использовать для указания размера большой стра­ ницы и связанного пула. Данный параметр указывается в байтах. Если раз­ мер страницы не указан, будет использоваться размер большой страницы по умолчанию и соответствующий пул. Параметр size устанавливает максимальное значение памяти, разрешенное для этой файловой системы (/mnt/huge ). Размер памяти может быть указан в байтах или в процентах от указанного пула больших страниц Размер округляется до границы Параметр (nr_hugepages). HPAGE_ SIZE. min_size устанавливает минимальное значение памяти, разрешен­ ное для файловой системы. Параметр min_size можно указать так же, как и размер: либо в байтах, либо в процентах от пула больших страниц. Во время монтирования количество больших страниц, указанное в параметре min _size, зарезервировано для использования файловой системой. Если сво­ бодных больших страниц недостаточно, монтирование не удастся. Когда большие страницы выделяются в файловой системе и освобождаются, счет­ чик резервов корректируется так, чтобы сумма выделенных и зарезервиро­ ванных больших страниц всегда была не меньше Опция nr_inodes устанавливает максимальное количество инодов, которые может использовать Если параметры min_size. /mnt/huge. size, min_size или nr_inodes не указаны в командной строке, ограничения не устанавливаются. Для параметров pagesize, size, min _size и nr_inodes вы можете использовать [Glg]/[Mlm]/[Klk] для представления гига/мега/кило. Например, size=2K имеет то же значение, что и size=2048. В то время как системные вызовы чтения поддерживаются для файлов, на­ ходящихся в файловых системах hugetlb, системные вызовы записи - нет. • I D - ··················································································
1!lава n..1nux ................. . Обычные команды chown, chgrp и chmod (с Х . Ущнш.1t·1111t• Н:1\НI 11.ю соответствующими разрешения- ' ми) можно использовать для изменения атрибутов файла на hugetlbfs. Кроме того, важно отметить, что такая команда монтирования не требует­ ся, если приложения будут использовать только системные вызовы shmget или mmap с МАР_HUGETLB. mmap с МАР_НUGETLB, посмотрите shmat/ Для примера того, как использовать на map_ hugetlb ниже. Пользователи, которые хотят использовать память hugetlb через сегмент об­ щей памяти, должны быть членами дополнительной группы, а системный администратор должен настроить этот gid в /proc/sys/vm/hugetlb_shm_group. Для одних ·и тех же или разных приложений можно использовать любую комбинацию вызовов mmaps и shm*, хотя для использования вызовов mmap без МАР_HUGETLB потребуется монтирование файловой системы. Системные вызовы, работающие с памятью, поддерживаемой страницами hugetlb, имеют только длину, соответс:гвующую собственному размеру стра­ ницы процессора; они обычно не будут работать, если для значение errno установлено EINVAL или будут исключены из страницы hugetlb, выходящие за пределы длины, если они не выровнены по большой странице. Например, munmap() завершится ошибкой , если память поддерживается hugetlb, а ее длина меньше, чем размер hugepage. 8.6. Практикум администратора 8.6.1. Полезные команды оболочки Файл Файл страницей /proc/meminfo /proc/meminfо содержит всю щ-1формацию, связанную с памятью. Для просмо1_-ра данного файла используйте команду cat: $ c at / pr oc/ meminf o • ... .. .. ... ...... ... ........ ..... .... ..... .. .... .. . .... .. .. . .. .... ........... .... ·· -
И , IJНI J ,illll\. ....................... n.1nux Рис. 8.4. Вывод команды (частично) cat lproc/meminfo Данная команда выводит множество параметров, связанных с памятью. Что­ бы получить информацию о физической памяти из файла /proc/meminfo, ис­ пользуйте : $ grep MemTotal /proc/meminfo MemTotal: 41185488 kB Чтобы получить информацию о виртуальной памяти из файла /proc/meminfo, используйте: $ grep VmallocTotal /proc/meminfo VmallocTotal: 34359738367 kB Команда Команда top и ее улучшенный вариант htop top позволяет отслеживать процессы и использование системных ресурсов в Linux в режиме реального времени. Когда вы запустите команду, • • - --------------···········--···-···--··--···--··--···--···-···-···--···-··--···-···
n..1пux ................. . ) Jlalla Х . У11р:111.11t·111н· 11:l~HI 11,Ю то заметите, что значения в выходных данных продолжают изменяться с не­ которым небольшим интервалом (рис. 8.5). о top Т,1 1, ".(р11( У.1В f 11 ',' U0 up }1'\ tnl 11, ) ]8 2 u , 41185488 total, •>1~m 1А ,,11р 3805992 frf"e, 20804600 tot,11, 20797564 free, (J.Jta 20 ",1184 •,>11,w·dat.J 20 20 с,;ч;<, ',7182 ':>031 57185 57183 57366 12733 8 57678 1 2 3 \,r,,,,.,,1 data my5ql 1<11·.-w·data www-data www-data wi....w··data root den;s root root .,,,мw root 4 root 6 root 7 root 9 10 11 12. 13 14 root root root root root root lS root 16 18 19 20 21 11 d.iy•, 16 • 1, 1 11~1!'•, ln,1d ;iv+ r,1gr' 6 r1н>1111g, 142 •lt>ep111~, 0 \op1<.,I 0 -;' 3 \., 0 0 nl, 79 4 111, 0 0 ,,,,1, 0 0 111 root ,0 20 20 20 20 20 20 20 20 20 0 0 20 20 0 -i54600 145S28 0 50'>176 196500 0 493760 183S32 0 :'3.302g 0.016t 0 515S12 205512 442032 133752 556824 240244 53.2.88 11816 0 42948 4112 225492 9000 0 0 ·20 ·20 0 19019640 7036 21888 S Ч.8 4q. 4i' ', 0.4 43.'41.7 32.9 0.5 22912 R 12 .0 0. 3 21400 R 10.0 0.6 56S6 S 0 I 0.0 R 1.3 0. 3 0.3 6420 S 0 S 0.0 0.0 0 I 0 I 0 I 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ЗЗS2 0 0 ct 20 0 ·20 ,. root ct root 0 Рис. На рис. 8.6 5 I S S S 5 ':, S S I S S 5 8.5. 0 0 1 , И 0 1 0: s-1 :я pr,:-, tr-n;•.: l ... t, ·,\ :,t,p fр'Т!/ .' 1: ~4 10 phV fµtn7 .' 4">01 i0 ,r,y,;qld 1: 38. 72 php-fpm7 _2 1:37.78 php-fpm7.2 0 59.89 php-fpm7.2 37 05.91 nginx 19 14. 34 rcu_c;ched 0 -1 ~ ':, 0.0 0.0 0.0 0 00.04 top 3 04.56 systemd 0 00.1~ kthreadd 0 35.68 kworker/0 0 0 00.00 k,~or~er:0:€\H 0 00.00 mrn_percpv __ wq 0 ..18. 73 i.so+-tirq,Ji0 0 00.00 ,·cu_Ьh 0 00.34 migro1,tion.·0 0 01 9б ,~atchdc,~/0 0 00.00 ~p;;hpi0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 00.00 е: 1-:. 00. 76 28, 1"1 cpuhpil 1,at:ch(1og: 1 n,igi·ation/1 kso-ftirad 1 00.е0 ~1-юr·ker 1 :0Н 00.00 cpuhp.-: 0 0: .19 ,~at::chdog/ 2 0 00. 76 migration.':;' Команда top приводится более продвцнутый ее вариант мимо всей информации, выводимой top, х f}l 18359856 h<Jft r,н~н, ]1649348 , нl .,,,,,. .224 ~6 <., 10 root r·oot Pd. 21196 ':. 17440S 22260 R r'"t ct 20 ц tJ't't: ' ("!НII• - команда htop. По­ данная команда выводит загрузку процессора по ядрам, а также выводит график используемой памяти. о 1 ] 1 J [ ""[ ] '. 1 ] I ' [ 1 11 118 1l• 3 [ 1 J I ] ] [ Рис. 8. 6. ] 1 н.l ] '\ 16 , • ,. • ] J R•> 1 ja,-,:;. Комапда i 1 1 [ 1 х , .'4 16 59 с:, 1 htop ..--.. ----.. -.------.--.--.----.. ---.--------.---.. ----.--.----.-... --... ------.. -ID
Sl. 1p11 J,i1111x ...................... n.lnLix Во всем эта программа лучше , но ее нужно установить отдельно (например, командой sudo apt install htop в DеЬiаn-подобных системах). Команда free Информация об используемой памяти выводится командами top и htop по­ мимо всего прочего. Но если вам нужно вывести информацию только об использовании памяти , тогда используйте команду free. По умолчанию зна­ чения для ка~ого поля указана в килобайтах, чтобы не пересчитывать в уме в мегабайты, используйте ключ Рис. На рис. 8.7 -h 8. 7. для более удобного формата вывода. Команда free показано, что всего установлено -h 39 Гб физической памяти (у нас виртуальный сервер, поэтому объем памяти не является степенью как обычно) , из них 17 используется (used), еще 17 Гб 2, отведено под буферы и кэш (эту память также можно считать свободной, поскольку в случае необходимости система будет выделять память из этой области) и полностью свободна. Также есть область подкачки из них используется ... 6.9 Мб, (Swap) размером поэтому можно считать, что все 3.6 Гб 19 Гб, 19 Гб подкачки свободно . • . . . -----------.. ----------------------. ---. --. --------------------------.. --.... -. •
n.iпux .. ..... .. ........ . I '.: 1ава Х. У11раи.1е1111r ШI\IЯ 11,ю Для сброса области буферов и кэша можно использовать команду: sudo echo 1 > / proc / sys /vm/ dr op cac hes Результат выполнения этой команды показан на рис. было свободно (free) 3.4 Гб, нения указанной команды для кэша используется уже lO Гб. Рис. 8.8. Сброс буферов и кэша в действии Команда Команда Linux, 8.8. Если до этого у нас 17 Гб, то после выпол­ всего 846 Мб , а свободно а для кэша было отведено vmstat - vmstat это инструмент мониторинга производительности в который предоставляет полезную информацию о процессах, памяти , операциях ввода-вывода, подкачке , диске и планировании процессора, а так ­ же приводит статистику виртуальной памяти вашей системы. $ vmstat • ··- ........ -.......... ··- -·-- .............. -...... -·- ---. -- -- .. -· ........ -·· ...... . .
Ядро Linux .................... ... n.inux 8.6.2. Интерфейс СМА Интерфейс отладки СМА полезен для извлечения базовой информации из различных областей СМА и для проверки выделения/освобождения в каж­ дой из областей. Каждая область СМА представляет каталог в <debugfs>/cma/, представлен­ ный своим именем СМА, как показано ниже: <de b ugfs>/cma/<cma name> Структура файлов, созданных в этом каталоге, выглядит следующим обра­ зом: • [RO] base_pfn: • [RO] count: базовый PFN (номер страницы кадра) зоны. объем памяти в области СМА. • [RO] order_per_Ьit: порядок страниц, представленный одним битом . • [RO] Ьitmap: битмап состояний страниц в зоне. • [WO] alloc: выделить N страниц из этой области СМА. Например, ко­ манда: e cho 5 > <debugf s>/ c ma /< cma_name >/ all o c попытается выделить • [WO] free: 5 страниц бесплатные N из области ста_ пате. страниц из этой области СМА, как описано выше. Примечание. WO означает "только для записи", RO - только для чтения. 8.6.3. Добавление файла подкачки Как правило, раздел подкачки создается при установке системы и не всегда • удобно менять структуру разделов уже после того, как система установле- 1D ....... -.. --... -.................... -------.. --.......... -.. --.--.---.--.... ---.-. •
1J 1ава t\.inux ----------···-···· Х. У11равJ 1с1шс 1щмя I ыо на. Однако , если вам понадобилось дополнительное пространство подкачки, выход есть - можно создать файл подкачки . Его производительность будет чуть ниже , чем у раздела подкачки , но как временный вариант (пока не уве­ личите размер ОЗУ) такая мера вполне сойдет. Первым дел о м. нужно создать собственно сам файл подкачки (в данном при­ мере мы создаем его размером 2 Гб , вы можете добавить больше подкачки , если есть свободное место на диске): $ sudo dd if=/dev/zero of=/swap - file count=2 bs=lGiB Затем установим права доступа и настроим область подкачки (команда mkswap): $ sudo chmod - v 0600 /swap - file $ sudo chown - v root : root /swap - file $ sudo mkswap /swap - file Осталось только активироват ь файл подкачки : $ sudo swap on /swap - file Чтобы уб~диться , что новый файл подкачки используется, введите команду: $ swapon -summary Осталось только добавить информаци ю о нем в файл /etc/fstab , чтобы систе­ ма не "потеряла " его после перезагрузки. Откройте файл /etc/fstab в любом текстовом редактор е и доб авьте строку (редактор нужно запускать через команду sudo , н апример , sudo joe /etc/fstab - мало ли, вдруг вы об этом за­ были): . /swap - file swap s~ap defaults О О •...--.. ·--.. -... --· .. -· .. -· .. -...... -.-----·. -.-· ··--.·--· .. -·. -..................1D
Глава 9. Файловая система и ядро
Ядро 9.1. Linux • _______________ : __ _____ n.iпux Виртуальная файловая система Linux Поскольку эта книга посвящена ядру, то в главе, посвященной файловой системе , мы рассмотрим как все устроено изнутри вместо рассмотрения ко­ манд для работы с файловой системой. Виртуальная файловая система (VFS, Virtual File System) - это программ­ ный уровень в ядре, который обеспечивает интерфейс файловой системы для программ пользоват ель ского пространства. Он также обеспечивает абстракцию внутри ядра, которая позволяет сосу­ ществовать различным реализациям файловой системы. Другими словами, ядро поддерживает множество самых разных фай.т,ювых систем - ext2, ехtЗ , ext4, XFS , ZFS и т.д. Чтобы пользователь мог использовать одни и те же ко­ манды (ер , mv, cat и т.д. ), а программист одни и те же системные вызовы для работы со всеми файл овыми системами , как раз и нужна виртуальная фай­ ловая система . В противном случае пришлось бы реализовывать отдельные команды для работы с каждой файловой системой , например, для работы с XFS коман да копирования ния - xfs mv. могла бы называться xfs_cp, а команда перемеще­ •
n.iпux ................. . 1. ,ака 9, Ф:iii.IOJШSI CIIC I t'\Ja 11 Sl , IJНI Системные вызовы зываются из VFS open(2), stat(2), read(2), write(2), chmod(2) и т. д. вы­ контекста процесса . Это также благодаря VFS, иначе пришлось бы создавать разные методы для работы с файлами, в зависимости от фай­ ловой системы . Настоящее бы веселье начал ось , когда нужно было скопи­ ровать файл из раздел а , отформатированного как ext4 в ХFS-раздел, то есть когда файловые системы на разделах не совпадают. Какую тогда команду использовать ext4_cp или xfs_cp? В общем , чтобы всех этих сложностей не было, как раз и был добавлен уровень абстракции , называемый виртуальн.ой файл овой сист емой . VFS реализует open(2), stat(2), chmod(2) и аналогичные системные вызовы. Передаваемый им аргумент pathname используется VFS для поиска в кэше записей каталога (также известном как кэш dentry или dcache). Он обеспе­ чивает очень быстрый м еханизм поиска для преобразования имени пути (имени файла) в определ енный dentry. Кэ ш "живет" в оперативной памяти и никогда не сохраняется на диск : он существуют только для повышения про­ изводительнос ти . Кэш dentry предназначен для просмотра всего вашего файлового простран­ ства. Поскольку большинство компьютеров не могут одновременно разме­ стить все записи кэ ша в ОЗУ, некоторые биты кэша отсутствуют. Чтобы пре­ образовать ваше имя пути в созданию dentry по dentry, VFS , возможно , придется прибегнуть к пути, а затем загрузить inode. Это делается путем поиска inode. Отдельный dent1y обычно имеет указатель на ин.дексный дескриптор (инод, inode) . Иноды -это объекты файловой системы, такие как обычные файлы, каталоги , FIFO и др . Они размещаются л ибо на диске (для файловых систем блочных . устройств) , л ибо в памяти (для псевдофайлов111х систем). Индекс­ ные дескрипторы , находящиеся на диске , при необходимости копируются в память , а изменения в индекс н ых дескрипторах записываются обратно на диск. На один индексны й дес криптор могут указывать несколько dentry (например , это делают жесткие ссыл ки) . Для поиска индекса нужно , чтобы VFS вызвала метод lookup() индекса роди­ тельского каталога. Данный метод устанавливается конкретной реализацией файловой системы , в которой находится индексный дескриптор. Как только у VFS есть требуемый dentry (и , следовательно, индексный дескриптор), мы можем делать все эти скучные вещи, такие как open(2) или stat(2) . • .............................................................................. ..... .
Я : tро l,inux Операция stat(2) _______________________ t'tinux довольно проста: как только сматривает данные VFS получает dentry, она про­ и передает часть их обратно в пространство поль­ inode зователя. Для открытия файла требуется еще одна операция: выделение файловой структуры (это реализация файловых дескрипторов на стороне ядра). Только • что выделенная файловая структура инициализируется указателем на и набором функций-членов файловой операции. Они взяты Затем вызывается файловый метод open(), dentry из данных inode. чтобы конкретная реализация файловой системы могла выполнять свою работу. Вы можете видеть, что это еще одно переключение, выполняемое VFS. Файловая структура помещает­ ся в таблицу файловых дескрипторов процесса. Чтение, запись и закрытие файлов (и друтие операции VFS) выполняются с использованием файлового дескриптора пользовательщюго пространства для захвата соответствующей файловой структуры , а затем вызова требуе­ мого метода файловой структуры для выполнения всего, что требуется. Пока файл открыт, он использует dentry, что, в свою очередь, означает, что индекс­ ный дескриптор 9.2. VFS все еще используется. Регистрация и монтирование файловой системы Следующие системные вызовы используются для регистрации и отмены ре­ гистрации файловой системы: #include <linux/fs.h > extern int register_filesystem (struct file_system_type *) ; extern int unregister_filesystem (struct file system_type *) ; Переданная структура .file_system _ type описывает вашу файловую систему. Когда делается запрос на монтирование файловой системы в каталог в ва­ шем пространстве имен , вызывает соответствующий метод VFS конкретной файловой системы. Новый возвращаемое вызовом vfsmount, mount() для ссылающийся на дерево, ->mount(), будет присоединен к точке монтирования, • так что при обращении к точке монтирования она будет указывать на ко- ID--------· .. --.. --·---...... --...... -·. ·---.. ·---··· ... --·. --.. -···---·· -· ......... . • •
1Jlalla 9 . Фaiim111as1 t.'l.1nux ... ............... . рень этого vfsmount. Все то же самое, как при монтировании через команд­ ную строку. Например, вы монтируете к устройство CIICll.'Ma 11 SЦJJO /dev/sda2. /mnt/sda2 (это точка монтирования) После монтирования каталог /mnt/sda2 будет предо­ /dev/sda2. ставлять доступ к корню файловой системы, размещенной на Файл /proc/filesystems содержит все файловые системы, поддерживаемые ядром. Cтpyктypafile_system_type описывает файловую систему. В ней определены следующие члены: struct file system_type { const char *name ; int fs_flags; struct dentry * (*mount ) (struc~ fйе system_type * const char * , void *); void (*kill sb) (struct super_Ыock *) ; struct module *owner ; struct file system_type * next ; struct list_head fs_supers ; struct lock_class_key s lock_key ; struct lock_class key s umount_key ; int , }; Описание членов структуры приведено в табл . Таблица 9.1. Описание членов cmpyкmypыfile_system_type Член структуры пате fs_Jl.ags mount kill- sb • 9.1. Описание Имя типа файловой системы , например, "iso9660", "xfs" "xt4", и т. д. Различные флаги вроде FS_REQUIRES_DEV, FS_ NO_DCACHE и т.д Метод, вызываемый при монтировании нового эк- земпляра этой файловой системы Метод, вызываемый при закрытии экземпляра файловой системы ..-. -- --.--------------------------------------------------------------------------1111
И J \IIO l .i1111x ....................... n.1n ux Для внутреннего использования owner VFS: в большинстве случаев вы д ол жны инициализировать его значением THIS- MODULE Для внутреннего использования next VFS : вы должны NULL инициализировать это значен!fе fs_supers Для внутреннего использования s_lock_key Зависит от блокировки s_ umount_ key Зависит от блокировки Аргументы метода Табл ица 9.2. mount() приведены в табл . Аргумен ты метода 9.2. mount() Описание Аргумент structfile_system_type *fs_type Структура типа (см. Флаги монтирования intflags const char *dev- file_system_type 9.1) табл. Имя монтированного устройства пате Произвольные параметры монтирования, обычно представляют собой стро - void *data ку Метод mount() ASCII должен возвращать корневую структуру дерева, запрошен ­ ную вызы вающей стороной. Активная ссылка на его суперблок должна быть получена , а суперблок должен быть заблокирован. В случае ошибки он дол­ жен вернуть ERR_ PTR. Аргум енты совпадают с аргументами mount(2), . и их интерпретация зави­ сит от типа файловой системы. Например , для блочных файловых систем пате интерпретируется как имя блочного устройства, это устройство dev - • . . . . . . -- .... . ---. ---.. ---. - . --. - ·... ---.... --...... -. -... -.. -.. -. ---. -. -. ---. - .. -. -- ,
n..1nux .................. . открывается , и если оно содержит подходящий образ файловой системы, ме­ тод соответственно создает и инициализирует структуру возвращая его корневой Метод мы - dentry struct super_Ыосk, вызывающей стороне. может вернуть поддерево существующей файловой систе­ ->mount() ему не нужно создавать новое . Основной результат с точки зрения вы­ зывающей стороны - ссылка на dentry в корне дерева для присоединения; создание нового суперблока является обычным побочным эффектом. Наиболее интересным элементом структуры суперблока, который заполня­ ет метод mount(), является поле "s_op". Это operations'!, которая описывает следующий указатель на "структуру super_ уровень реализации файловой системы. Обычно файловая система использует одну из общих реализаций mount() и вместо этого предоставляет обратный вызов fill_super() . Общие варианты : • mount_ bdev - смонтировать файловую систему, находящуюся на блочном устройстве. • mount_nodev - смонтировать файловую систему, которая не поддержива­ ется устройством. • mount_single - смонтировать файловую систему, которая разделяет экзем­ пляр между всеми монтируемыми. Реализация обратного вызова • struct super_Ыосk *sb - fill_super() имеет следующие аргументы: структура суперблока. Обратньхй вызов должен инициализировать ее надлежащим образом. • void *data - произвольные параметры монтирования, обычно представля­ ют собой строку • int silent- нужно 9.3. ASCII ли "молчать" об ошибке (1) или нет (О) Объект суперблока Объект суперблока представляет смонтированную файловую систему. '. --.. --.. -.-.. --.. ---.. -.... -.. ---.. --.. -.-.. --.. --.. ---................-... --.·1111
И , 1ро l ,i1111x ..... .. ... .. ........... ft1nux 9.3.1. Структура struct super_operations Описывает, как именно VFS может манипулировать ' суперблоком в вашей файловой системе. В ней определены следующие члены: struct super_operations { struct inode * (*all oc inode) (struct super_Ьlock *sb ); void (*destr oy_i node ) (struct inode *) ; vo id (*dirty_inode) (struct inode * , int flags); int (* write_inode ) (stru c t inode * , int) ; _ void (* drop_inode) (struct inode *) ; void (*delete_inode ) (struct inode *); void (*put super) (struct super_Ьlock *) ; int (* sync_fs ) (stru ct super_Ьlock *sb , int wait ); int (*freeze fs) (struct super_Ьlock *) ; int (*unfreeze f s ) (st ru ct supe r _Ьlock *) ; int (*statf s ) (struct dentry * , struct kstatfs * ); int (*remou nt fs) (struct super_Ьlock * , int * , char *) ; void (* c lear inode) (str uct inode *) ; void (*umount_begin) (struct super Ыосk *) ; int (*sho w o ptions) (struct seq_file * , struct dentry * ); ssize t (*quota_read ) (struct super_Ьlock * , int , char *, s i ze_t ,- • loff_t) ; ssize t (*quota_write) (struct super_Ыock * , int , const char * , size_t , loff_t ) ; int (*nr_ca c hed_o bje c ts) (s tru c t super _Ьlock *) ; void ( *free_cached_objects) (struct supe r _Ыock * , int) ; }; Все методы вызываются без каких-либо блокировок, если не указано иное . Это означает, что большинство методов можно безопасно блокировать. Все методы вызываются только из контекста процесса (т.е. не из обработчика прерывания или его нижней половины). Методы объекта суперблока при­ ведены в табл. Таблица 9.3. 9.3. Методы объекта суперблока • . . ...................... ............................................................
) " 1ава 9. Фаiiлои:Ш CIICICJ\1:1 11 Sl,' \()O n.1nux ...... .. . . ....... . Оп ис ан ие Метод Данный метод вызы1:шется alloc_inode() для выде­ inode и ее инициализа­ ления памяти для структуры alloc inode ции . Если эта функцl:Я не определена, выделяется простой "struct inode" . Обычно alloc_inode использу­ ется для выделения более крупной структуры , кото­ рая содержит встроенный в нее "struct inode" Данный метод вызьiвается вобождения ресурсов, destroy_inode destroy_inode() для ос­ выделенных для struct inode. Это нужно только в том случае, если была определе­ на функция ->alloc_inode, и она просто отменяет все действия, сделанные функцией ->alloc _inode Данный метод вы;3ывается виртуальной файловой системой, когда индексный дескриптор помечен как грязный. Обратите внимание: как грязный помеча­ ется сам инод, а не его данные. Если обновление dirty_inode должно быть сохранено с помощью . fdatasync() , тог­ да 1_DIRTY_ DATASYNC будет установлен в аргу­ менте флагов. 1_DIRTY_ ТIМЕ будет установлено во флагах в случае, если включено отложенное время, и struct inode имеет время обновления с момента по­ следнего вызова Метод вызывается, когда write inode ->dirty_inode VFS необходимо записать индексный дескриптор на диск . Второй параметр указывает, должна ли запись быть синхронной или нет, не все файловые системы проверяют этот флаг Вызывается, когда последний доступ к индекс­ ному узлу отбрасывается с удерживаемой спин­ блокировкой drop_inode inode->i_lock. Этот метод должен быть либо NULL (нормальная семантика файловой системы UNIX), либо "generic_delete_inode" (для файловых систем, которые не хотят кэшировать индексные дескрипторы, что приводит к тому, что "delete_inode" всегда вызывается независимо от зна­ чения i_ nlink) •-~ -----------------------. ---------.-------------. --. -.--.-.· -----. -----------------1111
И , 11111 l.i1111, delete- inode ....................... ftlnux Вызывается , когда Вызывается , когда put_super VFS VFS хочет удалить индекс хочет освободить суперблок (т,е. размонтировать). Обычно вызывается при удер- живаемой блокировке суперблока Вызывается , когда sync.Js VFS записывает все грязные данные, связанные с суперблоком . Второй параметр указывает, должен ли метод ожидать завершения за~ писи. Необязательный метод Вызывается , когда freeze.Js VFS блокирует файловую систе- му и переводит ее в согласованное состояние. Этот метод в настоящее время используется диспетчером логических томов unfreeze.Js statfs Вызывается , когда VFS (LVM) разблокирует файловую си- стему и снова делает ее доступной для записи Вызывается , когда VFS необходимо получить стати- стику файловой системы Вызывается при перемонтировании файловой систе- remount.Js мы. Метод вызывается с удерживаемой блокировкой ядра clear- inode umount_ begin show_ options quota read Если вызывается , то VFS очищает индексный дескриптор. Необязательный метод Вызывается , когда VFS размонтирует файловую систему Вызывается VFS для отображения параметров мои- тирования для Вызывается VFS /proc/<pid>/mounts для чтения из файла квоты файло вой системы 11!1- - ---------------------~-------·--···---·--··---··-········-·--------·--·--···--- '
) Jl:111:1 n..1nux .................. . Вызывается quota_ write VFS 9 . Фаiiло11:ш CIJClt.'M:I 11 SЩl)CI для з аписи в файл квоты файло во й системы Вызывается функцией сокр ащения кэша sb для фай- ла вой системы , чтобы вернуть количество содер- nr_cached_objects жащихся в ней свободных кэшированных объектов . Необязательный метод Вызывается функцией сокращения кэша sb для файловой системы , чтобы сканировать указанное количество объектов , чтобы попытаться их освобо - дить. Необязательно , но любая файловая система, реализую щая этот метод, должна также реализ ов ать ->nr_ cached _ objects, чтобы он вызывался правильно. Мы ничего не можем сделать с ошибками, с которыми может столrшуться файловая система, отсюда и free _ cache_ objects возвращаемый тип void. Реализации должны включать условные вызовы повторного планирования внутри любого выпал няемого цикла сканирования. Это позволяет VFS определять подходящие размеры пакето"в сканирова- ния , не беспокоясь о том, не вызовут ли реализации проблемы задержки из-за больших размеров пакетов сканир ования 9.3.2. Структура struct xattr_handlers В файл овых системах , поддерживающих расш иренные атрибуты поле суперблока s_xattr указывает на массив обработчиков ющийся нулем . Расширенные атрибуты • пат е - - (xattrs ), xatt,-, оканчива­ это пары имя:значение : указывает, что обработчик сопоставл я ет атрибуты с указанным именем (например , "system.posix_acl_access"); поле префикса должно быть • NULL. .---.----.. --.-.------...-.. ---.---.-.------.-.-.... ---.---.----... -.-... ---.-----Cil •
Я , 1р11 l.iJHI\ ....................... f.l1nux • prefix - указывает, что обработчик сопоставляет все атрибуты с указанным префиксом имени (например, "user"); поле имени должно быть NULL. • list - определяет, должны ли атрибуты, соответствующие этому обработ­ чику xattr, быть перечислены для определенного dentry. Используется не­ которыми реализациями listxattr, такими как generic _listxattr. • get - вызывается VFS для получения значения определенного расширен­ ного атрибута . Этот метод вызывается системным вызовом • set - вызывается VFS getxattr(2). для установки значения определенного расширен­ ного атрибута. ~огда новое значение равно NULL, вызывается для уда­ ления определенного .расширенного атрибута. Этот метод вызывается системными вызовами 9.4. setxattr(2) и removexattr(2). Объект инода Объект инода представляет собой объект внутри файловой системы. Струк­ тура struct inode_operations описывает, как именно VFS может манипулиро­ вать инодами в файловой системе . Структура описана так: struct inode_operations { int (*create) (struct user_namespace *, struct inode *, struct dentry *, umode_t , bool) ; struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int) ; int (*link) (struct dentry *,struct inode *, struct dentry *) ; int (*unlink) (struct inode * , st r uct dentry *); int (*symlink) (struct user_namespace *, struct inode *, struct dentry *, const char *) ; int (*mkdir) (struct user_namespace *, struct inode *, struct dentry *, umode_t) ; int (*rmdir) (stru.c t inode * , struct dentry *); int (*mknod) (struct user_namespace *, struct inode *, struct dentry *, umode_t , dev_t) ; int (*rename) (struct user_namespace *, struct inode *, struct dentry *, struct inode *, struct dentry * , unsigned int); int (*read lin k) (struct dentry * , char _user * , in t); const char * ( *get link) (struct dentry * , struct inode * , struct delayed_call *); int ( *permission) (s truct user_ namespace *, struct inode *, int) ; struct posix_acl * (*get inode acl) (struct inode * , int, bool); int (*setattr) (struct user_namespace * , struct dentry *, struct iattr *) ; 1111- :·-------------------------···:··------------------ ----------- ---- -- --- ---------'
n.1пux .................. . 1 . rава 9. (l):1ii.юн:н1 Cll{'ll'M:t II щ1ро int (*getattr) (struct user_namespace * , const struct path *, struct kstat *, u32 , unsigned int) ; ssize_t (*listxattr) (struct dentry * , char * , size_t); void (*update time) (struct inode * , struct timespec * , int); int (*atomic_open) (struct inode *, struct dentry * , struct file * , unsigned open_flag , umode t create_mode); int (*tmpfile) (struct user_namespace * , struct inode * , struct file * , umode_t) ; struct posix_acl * (*get_acl) (struct user_namespace *, struct dentry *, int) ; int (*set_ acl) (struct user_namespace * , struct dentry * , stru c t posix_acl * , int) ; int (*fileattr_set) (struct user_ namespace *mnt_userns , struct dentry *dentry, struct fileattr *fa); int (*fileattr_get) (struct dentry *dentry , struct fileattr *fa) ; }; Нужно отметить, что все методы (табл. 9.4) могут вызываться без каких­ либо блокировок. Таблица 9.4. Методы объекта инодов Метод Описание Вызывается системными вызовами open(2) и creat(2). Требует- ся только в том случае, если вы хотите поддерживать обычные create файлы. Записи dentry, которые вы получаете, не должны иметь индекса (то есть это должен быть отрицательный вы , вероятно, вызовете dentry) . Здесь d_instantiate() с dentry и только что соз• данным индексным дескриптором Вызывается, когда VFS необходимо найти индексный дескрип- тор в родительском каталоге. Имя, которое нужно искать , на• ходится в dentry. lookup d_add(), чтобы "i_count" в структуре Этот метод должен вызвать вставить найденный inode в dentry. Поле inode должно быть увеличено. Если указанный inode не существует, в dentry следует вставить NULL inode (это называется отрицательным dentry). Возврат ко.1;1а ошибки из этой подпрограммы должен выполняться только при реальной ошибке , иначе создание как inode с помощью системных вызовов , таких create(2), mknod(2), rnkdir(2) хотите перегрузить методы и т. д., не удастся. Если вы dentry, вам следует инициали- "d_dop" в dentry; это указатель на структуру "dentry_operations". Этот метод вызывается с удерживаемым зировать поле ~, семафором индексного дескриптора каталога .. ... . .... .. ... . .. .. .... .... . ..... -···- ·· . ... . ...... -- .... ...... . ····--· ....... --- -
Я . 1ро (,iш1, ................. .-..... Вызывается системным вызовом link Вам , вероятно, потребуется вызвать d_instantiate() create() Вызывается системным вызовом в так же, как в unlink(2) . Требуется только в том случае, если вы хотите поддерживать удаление инодов Вызывается системным вызовом symlink link(2). Требуется только том случае, если вы хотите поддерживать жесткие ссылки . методе unlink t\.iпux symlink(2). Требуется только в том с лучае, если вы хотите поддерживать символические ·ссылки . Вам, вероятно , потребуется вызвать d_instantiate() так же, как в методе create() Вызывается системным вызовом mkdir rnkdir(2). гов. Вам, вероятно, потребуется вызвать d_instantiate() create() как в методе rmdir Вызывается системным вызовом rmdir(2). так же , Требуется только в том случае, если вы хотите поддерживать удаление подкаталогов Вызывается системным вызовом устройства mknod Требуется только в том случае, если вы хотите поддерживать создание подкатало ­ (char, mknod(2) для создания Ыосk) , именованного канала '· (FIFO) inode или со- кета . Требуется только в том случае, если вы хотите поддерживать создание этих типов инодов . Вам , вероятно , потребуется вызвать d_instantiate() так же , как в методе Вызывается системным вызовом create() rename(2) для переименова­ ния объекта , чтобы родитель и имя были заданы вторым индексным узлом и dentry. Файловая система должна возвращать -EINVAL для любых не­ поддерживаемых или неизвестных флагов . В настоящее время реализованы следующие флаги:(!) RENAME_NOREPLACE: этот флаг указывает, что если цель переименования существу - rename ет, переименование должно завершаться с ошибкой -EEXIST вместо замены цели. VFS уже проверяет существование, по­ этому для локальных файловых систем реализация RENAME_ NOREPLACE эквивалентна простому переименованию. (2) RENAME_EXCHANGE: обмен источником и целью . Оба должны существовать; это проверяется VFS. В отличие от про­ стого переименования , источник и цель могут быть разных ти пов ., . ...................................................................................
Глава n..inux __ ____ __ ___ ___ __ ___ Вызывается get_link VFS 9. Файловая сисrема и ядро для перехода по символической ссылке к индексному узлу, на который он указывает. Требуется только в том случае, если вы хотите поддерживать символические ссылки Теперь это просто переопред еление для использования readlink readlink(2) в случаях, когда ->get_link использует ndjump_ link() или объект на самом деле не является символической ссылкой. Обычно файловые системы должны реализовы вать ->get_link только для символических ссылок, и readlink(2) бу- дет использовать это автоматически Вызывается permission VFS для проверки прав досту па к рую rcu-walk не может обработать , верните снова будет вызван в режиме setattr getattr listxattr POSIX- подобной файловой системе. Если возникает ситуация, кото- -ECHILD, ref-walk и он Вызывается зывается VFS для установки атрибутов файла. Этот метод выchmod(2) и соответствующими системными вызовами Вызывается вызывается Вызывается VFS для получения атрибутов файла. Этот метод stat(2) и соответствующими системными вызовами VFS для отображения всех расширенных атрибутов данlistxattr(2) ного файла. Этот метод вызывается системным вызовом Вызывается update_time VFS для обновления определенного времени или i_version индексного дескриптора. Если это не определено, VFS сама обновит индекс и вызовет mark_inode_dirty_sync Вызыв ается последний открытый компонент. Используя этот необязательный метод, файловая система может искать, возможно, создавать и открывать файл за одну атомарную операцию. Если он хочет оставить фактическое открытие для вызывающей стороны (например, если файл оказался символической ссылкой, устройством или просто чем-то, для чего файловая система не будет выполнять атомарное открытие), он atomic_ ореп может сигнализировать об этом, возвращая dentry). finish _ no_ open(file, Этот метод вызывается только в том случае, если по- следний компонент отрицателен или нуждается в поиске. Кэшированные пол ожительные записи dentry по-прежнему f_op->open(). Если файл был создан, флаг FMODE_CREATED должен быть установлен в файл->f_mоdе. В случае О_EXCL метод должен быть успешным только в том случае, если файл не существует, и, следовательно, FMODE_ CREATED всегда долже н быть установлен в случае успеха обрабатываются .,.... --... -.. ---.--.----.-.-----.-.·-------.. -.-.. --.--------.--.. -..... --.. --.----1111
Я J tpo (,iщ1х : .............. _....... t\.inux Вызывается в конце О TMPFILE open(). Необяза:гельно, эквивалентно атомарному ~озданию, открытию и удалению файла в ·заданном каталоге. В случае успеха необходимо вернуться с tmp.file уже открытым файлом; это можно сделать, вызвав finish_open_ simple() прямо в конце Вызывается в ioctl(FS_IOC_GETFLAGS) и ioctl(FS_IOC_ FSGETXATTR) для получения различных флагов и атрибутов .fileattr_get файлов. Также вызывается перед соответствующей операцией SET, чтобы проверить, что изменяется (в данном случае с за- блокированным эксклюзивным вернитесь к Вызывается в .fileattr_ set FSSETXATTR) i_rwsem). Если f_op->ioctl() ioctl(FS_IOC_SETFLAGS) ioctl(FS_IOC_ для изменения флагов и атрибутов различных файлов. Вызывающие удерживают эксклюзивный Если не установлено, вернитесь к 9.5. и не установлено, i_rwsem. f_op->ioctl() Объект адресного пространства 9.5.1. Общая информация Объект адресного пространства используется для группировки и управле­ ния страницами в кэше страниц. Его можно использовать для отслеживания страниц в файле (или чего-либо еще) , а также для отслеживания отображе­ ния разделов файла в адресные пространства процесса. Существует ряд различных, но связанных между собой услуг, которые мо­ жет предоставлять адресное пространство. К ним относятся сообщение о нехватке памяти, поиск страниц по адресу и отслеживание страниц, поме­ ченных как "грязные" (dirty) или "обратная запись" (writeback). Первый можно использовать независимо от остальных. ВМ может попы­ таться либо записать грязные страницы, чтобы очистить их, либо выпустить чистые страницы, чтобы использовать их повторно. Для этого он может вы­ зывать метод фолиантов - ->writepage для грязных страниц и ->release_folio для чистых (folios) с установленным флагом private. Чистые страницы без PagePrivate и без внешних ссылок будут выпущены без уведомления в адрес­ ном пространстве . --.. ----------------. --------. ---. -------------. ---. ---- . ---. ------------------_,
J 1,111,1 1) (J):lli . 11111:HI Cllt' 1 t'\1:1 11 11 IIIO n.1nux .................. . Примечание. Фолианты (folios) памяти Linux предназначены для того, чтобы файловые системы и кэш страниц могли управ• лять памятью фрагментами, превышающими размер страницы по умолчанию. Для достижения этой функциональности страницы должны быть помещены в LRU с lru_cache_add, а mark_page_active должен вызываться всякий раз, когда страница используется. Страницы обычно хранятся в индексе системы счисления с помощью ->index. Это дерево поддерживает информацию о статусе PG_Dirty и PG_ Writeback каждой страницы, так что страницы с любым из этих флагов можно быстро найти. • Тег Dirty в основном используется mppage_ writepages - методом по умол­ -->.writepages. Он использует тег для поиска грязных страниц для вызова ->writepage. Если mpage_writepages() не используется (т. е. адрес предоставляет свой собственный -->writepages), тег PAGECACHE_TAG_ DIRTY практически не используется. write_inode_now и sync_inode ис­ пользуют его (через _sync_single_inode), чтобы проверить , удалось ли ->writepages записать все адресное пространство address_space. чанию Тег обратной записи используется функциями через filemap Jdatawait_range filemap*wait* и sync_page* для ожидания завершения всей обратной за­ писи. Обработчик адресного пространства может прикреплять к странице до­ полнительную информацию, обычно используя поле "private" на "странице структуры". Если такая информация прикреплена, должен быть установлен флаг PG_Private. Это заставит различные подпрограммы виртуальной маши­ address_space для обработ­ ны делать дополнительные вызовы обработчику ки этих данных . Адресное пространство действует как промежуточное звено между храни­ лищем и приложением . Данные считываются в адресное пространство по целой странице за раз и предоставляются приложению либо путем копиро­ вания страницы, либо путем отображения страницы в памяти. Данные за­ писываются в адресное пространство приложением, а затем записываются обратно в хранилище , как правило , целыми страницами , однако адресное пространство писи • address_space имеет более точный контроль над размерами за­ . ·-------------------------- ------- ---------------------------- -------------------- 8 : D
Я , tро l , i1111, ....................... rlinux Процесс чтения по существу требует только "read_ folio", Процесс записи бо­ лее сложен и использует write_ begin/write_ end или dirty Jolio для записи дан­ ных в адресное пространство address_space, а также writepage и writepages для обратной записи данных в хранилище. Добавление и удаление страниц в/из адресного пространства защищено mutex индексного i_ дескриптора . Когда данные записываются на страницу, должен быть установлен флаг PG_Dirty. Обычно он остается установленным до тех пор, пока writepage установить PG_ не попросит его записать. Это должно очистить PG_ Dirty и Writeback. На самом деле его можно записать в любой момент после очистки PG_Dirty. Как только становится известно, что он безопасен, PG_Writeback очищается. Обратная запись использует структуру операциями . Это дает операциям writeback_contro/ для управления writepage и writepages некоторую инфор­ мацию о характере и причине запроса обратной записи , а также об ограни­ чениях, при которых они выполняются. 9.5.2. Большинство Обработка ошибок во время обратной записи приложений, выполняющих буферизованный периодически используют вызов синхронизации файлов ввод-вывод, (fsync, fdatasync, msync или sync_file _range ), чтобы убедиться , что записанные данные попали в резервное хранилище. Когда возникает ошибка во время обратной записи, они ожидают, что об этой ошибке будет сообщено при выполнении запроса .на синхронизацию файлов. После получения сообщения об ошибке в одном запросе последующие запросы к тому же файловому дескриптору должны возвращать О, если только после предыдущей синхронизации файлов не воз­ никло новых ошибок обратной записи. В идеале ядро будет сообщать об ошибках только в тех описаниях файлов, в которых были выполнены записи, которые впоследствии не удалось записать обратно. Однако универсальная инфраструктура кэша страниц не отслеживает описания файлов, которые загрязнили каждую отдельную страницу, поэтому определить, какие файловые дескрипторы должны воз­ вращать ошибку, невозможно. • at-· ................................................................................
1 1,111а !) (J);1ii.1111нн1 t·11t·н·,ш 11,111ю n.inux .................. . Вместо этого универсальная инфраструктура отслеживания ошибок с обрат­ ной записью в ядре разрешает сообщать об ошибках в fsync для всех опи­ саний файлов , которые были открыты во время возникновения ошибки. В ситуации с несколькими модулями записи все они вернут ошибку при после­ дующей fsync, даже если все записи, выполненные через этот конкретный файловый дескриптор, завершились успешно (или даже если записи в этот файловый дескриптор вообще не производились). Файловые системы , которые хотят использовать эту инфраструктуру, долж­ ны вызывать функцию тар _set_error для записи ошибки в адресном про­ странстве , когда она возникает. Затем , после обратной записи данных из кэш а страниц в операции advance_wb_err, чтобы file->fsync, они должны вызвать .fi[f:_ check_and_ убедиться , что курсор ошибки файла структуры пе­ реместился в правильную точку в потоке ошибок, выдаваемых поддержива­ ющим устройством (устройствами). 9 .5.3. Структура sutruct address_ space_ operations Данная структура описывает, как VFS может манипулировать сопоставлени­ ем файла с кэшем страниц в вашей файловой системе. Содержит следующие члены: struct address space_ operati o ns { int (*writepage) (struct page *page, struct writebac k_cont r ol *wb c ); int (*read_folio) (struct file * , struct folio * ) ; int (*writepages) (struct address_space *, struct writeback_ control *) ; , boo l (*dirty_foli o ) (struct add r ess_space * , struct fol i o * ) ; void (*readahead ) (struct readahead_control *) ; int (*write_begin) (struct fi l e * , struct address _ space *mapp ing , loff_ t pos , unsigned len , struct page **pagep , void **fsdata) ; int (*write end) (struct file * , st r uct address_space *mapp ing , loff_t pos , uns i gned len , unsigned copied , stru c t p a ge *page , void *fsdata) ; sect o r_t (*bmap) (struct address_space * , sector_t ); void (*invalidate_ f o lio) (struct folio *, size_ t start , size t l en ) ; b oo l (*release f o lio) (struct folio * , gfp t ); vo id (*free foli o ) (struc t f o lio *) ; ssize t (*direct IO) (struct kiocb * , struct iov ite r *ite r ) ; int ( ~migrate_folio) (struct mapping * , struct folio *dst , struct f o lio *src , enum migrate_mode) ; ........................................ . .................................... .. .. .
И , 11ю l ,i1111, ............... . . ___ ... t\.1nux int (*launder_folio) (struct folio *) ; bool (*is_partially_uptodate) (struct folio * , size_t f r om , size_t count) ; void (*is_dirty_writeback) (struct folio * , bool * , bool *) ; int (*error_remove_page) (struct mapping *mapping , struct page *page ); int (*swap_activate ) (struct swap_info_struct *sis , struct file *f , sector_t *span) int (*swap_deactivate) (struct file *) ; i n t (*swap_rw ) (struct kiocb *iocb , s t ruct iov i ter *iter ); }; Таблица 9.5. Члены структуры address_space_operations Член структуры Описание Вызывается виртуальной машиной для записи грязной страницы в резервное хранилище, Это может произойти из соображений целостности данных (например, "синхронизации") или для освобождения памяти (сброс), Раз- ницу можно увидеть в wbc->sync_mode. Флаг PG_Dirty PageLocked равно true. writepage должен должен установить PG_Writeback и убе- снят, а значение начать запись, диться , что страница разблокирована , либо синхронно , writepage либо асинхроюю, когда операция записи завершится. Если wbc->sync_mode равен WB_SYNC_NONE, ->writepage не нужно слишком стараться , если есть проблемы , и может выбрать запись других страниц из сопоставления , если это проще (например , из-за внутренних зависимостей) . Если он решит не начинать за- пись, он должен вернуть АОР _ WR1TEPAGE_ACTIVATE, чтобы виртуальная машина не продолжала вызывать ->writepage на этой странице • I D - ---------------------------------·-·····-----------··:···------------------------·
1.1,ша 9. Фаii . ~овая с11с1е,ш II s1.1po n.inux _________________ _ Вызывается кэшем страниц для чтения фолианта из ре­ зервного хранилища. Аргумент "файл" предоставляет информацию для аутентификации в сетевых файловых системах и обычно не используется блочными файловы­ ми системами. Он может быть равен NULL, если у вызы­ вающей стороны нет открытого файла (например , если ядро выполняет чтение для себя, а не от имени процесса пользовательского пространства с открытым файлом). Если сопоставление не поддерживает большие фолиан­ ты, фолиант будет содержать одну страницу. Фолиант будет заблокирован при вызове read_folio. Если чтение завершается успешно, фолио должно быть помечено как актуальное. Файловая система должна разблокировать фолио после завершения чтения, независимо от того, было ли оно успешным или нет. Файловой системе не _нужно изменять счетчик ссылок на фолио; кэш страницы содержит счетчик ссылок, и он не будет выпущен, пока фолио не будет разблокировано . readJolio Ф айловые системы могут реализовывать ->read_ folio() синхронно . При нормальной работе фолианты читаются с помощью метода ->readahead(). Только в случае не- удачи или если вызывающей стороне нужно дождаться завершения чтения, кэш страницы вызовет ->read_folio(). Файловые системы не должны пытаться выполнить соб­ ственное упреждающее чтение в операции ->read_folio(). Если файловая система не может выполнить чтение в данный момент, она может разблокировать фолиант, выполнить любое действие, необходимое для обеспе ­ чения успешного чтения в будущем, и вернуть АОР _ TRUNCATED_PAGE. В этом случае вызывающая сто­ рона должна найти фолиант, заблокировать его и снова вызвать ->read folio. Вызывающие могут вызывать метод мую, но использование ->read_fo lio() напря­ read_mapping_folio() позаботится о блокировке, ожидании завершения чтения и обработке таких случаев, как АОР _ TRUNCATED_PAGE • .-------------------------------------------- -------------------.. --.---------.---tв
И . 1р11 l.i1111, ....................... n..inux Вызывается виртуальной машиной для записи страниц, связанных с объектом address _ space. Если wbc·>sync _ mode равен WB_SYNC_ALL, то writeback_control укажет диапазон страниц, которые должны быть записаны . Если writepages это WB_SYNC_NONE, то дается nr_to_write и , по воз- можности, должно быть записано столько страниц . Если параметр •>writepages не указан, вместо него используmpage_writepages. Он выберет страницы из адресного пространства, помеченные как DIRTY, и передаст их •>writepage ется Вызывается виртуальной машиной, чтобы пометить фолиант как грязный . Это особенно необходимо, если адресное пространство связывает личные данные с фо• dirtyJolio лио, и эти данные необходимо обновлять, когда фолиант "загрязняется". Он вызывается, например, при измене- нии отображаемой страницы памяти. Если он определен, он должен установить флаг ка dirty фолианта и метку PAGECACHE_TAG_DIRTY в i_pages поис• Вызывается виртуальной машиной для чтения страниц, связанных с объектом address_ space. Страницы расположены последовательно в кэше страниц и заблокированы. Реализация должна уменьшать счетчик ссылок на страницу после запуска ввода- вывода на каждой странице . Обычно страница будет разблокирована обработчиком завершения вводавывода. Набор страниц делится на несколько страниц синхронизации, за которыми следуют нескол ько асинхронных страниц, член readahead rac->ra->async_ size дает количество асинхронных страниц . Файловая система должна попытаться прочитать все страницы синхронизации , но может решить остановиться , как только достигнет асинхронных страниц . Если будет решено прекратить попытки ввода-вывода, можно просто выполнить retum. Вызывающий удалит оставшиеся страницы из адресного пространства, разблокирует их и уменьшит счетчик ссылок (refcount) PageUptodate, если ввод •вывод Установка PageError на л юбой на страницы . Установите завершился успешно. странице будет проигнорирована; просто разблокируйте страницу, если произойдет ошибка ввода•вывода 4 ' ID- .. --. -----. ------------------------------.---. --------------. -------------------.
1 1ава !) (J).til. IOll,HI CIH' 1 t'\J.I 11 SI IIНI rtinux ............. _____ _ Вызывается общим кодом буферизованной записи, чтобы попросить файл овую систему подготовиться к записи длинных байтов по заданному смещению в файле. dress _space должен Ad- проверять возможность завершения записи , выделяя пространство, если это необходимо , и выполняя любые другие внутренние операции. Если запись будет обновлять части любых базовых блоков в хранилище , то эти блоки должны быть предварительно write_ begin прочитаны (если они еще не были прочитаны) , чтобы обновленные блоки можно было правильно записать. Файловая система должна возвращать заблокированную страницу кэша страниц для указанного смещения в *pagep, чтобы вызывающая сторона могла выполнять запись . Возвращает О в случае успеха; < О в случае сбоя (это код ошибки) , и в этом случае write_end не вызьIВается После успешного выполнения write_begin и копирования write_end. len - это исходв write_ begin, а copied - это раз- данных необходимо вызвать ная длина, переданная мер, который удалось скопировать. write end Файловая система должна позаботиться о разблокировке страницы и освобождении ее лении Возвращает <О refcount, - Size. а также об обнов- 1 в случае ошибки, в противном случае количество байтов (<= "скопировано") , которые удалось скопировать в кэш страниц Вызывается виртуальной файловой системой для сопоставл ения смещения логического блока внутри объекта с номером физического блока. Этот метод используется ioctl Ьтар FIВMAP и для работы с swар-файлами. Чтобы мож- но был о переключиться на файл, файл должен иметь стабильное сопоставление с блочным устройством. Система подкачки не проходит через файловую систему, а вместо этого использует bmap, чтобы узнать, где находятся бло- ки в файле , и напрямую испол ьзует эти адреса • ·················································································· - I D
Я . tро l.iпux ____________ ........... t'1..inux Если фолиант содержит приватные данные, тогда будет вызываться invalidate_folio, когда часть или весь фолиант должен быть удален из адресного пространства . Обычно это соответствует усечению, перфорации или полному аннулированию адресного пространства (в последнем случае "смещение" всегда будет равно О , а "длина" invalidateJolio folio_size()) . Любые личные данные, - связанные с фоли- антам , должны быть обновлены, чтобы отразить это усечение . Если смещение равно О, а длина равна fo\io_size(), то личные данные должны быть освобождены, потому что фолиант должен быть полностью отброшен . Это можно сделать, вызвав функцию _ ->rеlеаsе_fоliо, но в этом случае выпуск ДОЛЖЕН завершиться успешно Вызывается для фолианта с закрытыми данными, чтобы сообщить файловой системе, что фолиант будет освобожден. Метод ->release_fo\io должен удалить все лич- ные данные из фолианта и снять флажок "приватный" . Если функция release_folio() должна возвращать значение завершается ошибкой, она false. release_folio() исполь- зуется в двух разных, но связанных случаях . Во-первых, когда виртуальная машина хочет освободить чистый releaseJolio фолиант без активных пользователей. В случае успеха ->release_folio фолиант будет удален из address_space и освобожден. Второй случай - когда был сделан запрос на аннули- рование некоторых или всех фолиантов в address_ space. Если файловая система делает такой В1'IЗОВ , она должна быть уверена, что все фолианты признаны недействительными Вызываетс:я , когда фолиант больше не отображается в freeJolio кэше страниц , чтобы разрешить очистку любых личных данных Вызывается общими процедурами чтения/записи для выполнения direct- !О direct_IO - то есть запросов ввода-вывода, которые обходят кэ ш страниц и передают данные неттосредственно между хранилищем и адресным простран- ством приложения • 8 1 8 · · · · ·-····-·······································································
I . ,ана n.inux _________________ _ 9. Фаii.1овая c11cIr\la II sI.1po Используется для сокращения использования физиче­ ской памяти. Если виртуальная машина хочет переме­ стить фолиант (возможно, с запоминающего устройства, migrateJolio сигнализирующего о неизбежном сбое), она передаст этой функции новый фолиант и старый фолиант. Метод migrate_fo\io должен передавать любые личные данные и обновлять все имеющиеся у него ссылки на .фолиант Вызывается перед освобождением фолианта launderJolio - для oб- ратноif записи "грязного" фолианта. Фолиант остается заблокированный на протяжении всей операции Вызывается виртуальной машиной при чтении файла из кэша страниц, когда базовый размер блока меньше paз- is_partially_uptodate мера фолианта . Если требуемый блок актуален, то чтение может завершиться без необходимости ввода-вывода для обновления всей страницы Вызывается виртуальной машиной при попытке вос­ становить фолиант. Виртуальная машина использует "грязную" информацию и информацию обратной записи, чтобы определить, нужно ли ей останавливаться, чтобы дать очистителям шанс завершить некоторые операции ввода-вывода. Обычно она может использовать is_ dirty_ writeback test_dirty и folio _ test_ writeback, folio_ но некоторые файловые системы имеют более сложное состояние (нестабильные фолианты в NFS предотвращают восстановление) или не устанавливают эти флаги из-за проблем с блокиров­ кой. Этот обратный вызов позволяет файловой системе указать виртуальной машине, следует ли рассматривать фолиант как грязный или с обратной записью в целях приостановки Обычно устанавливается в geпeric _ error_remove_ error_remove_page page, если усечение допустимо для этого адресного пространства. Используется для обработки сбоев памяти • .------------------.. ---- ----.---------- -------------.. --.. ------------.. --.. ------&1 •
}t , чт l.itlll\ ...................... . r.l1nux Вызывается для подготовки данного файла к обмену. Он должен выполнять любую проверку и подготовку, необходимые для обеспечения того, чтобы запись могла вы- полняться с минимальным выделением памяти. Он должен вызывать swap_activate функцию add_ swap_ extent() или вспомогательную iomap_swapfile_activate() и возвращать коли- чество добавленных экстентов . Если ввод-вывод должен быть отправлен через ->swap_rw(), он должен устаноSWP _FS _ OPS, иначе ввод-вывод будет отправлен непосредственно на блочное устройство sis->bdev вить Вызывается во время swapoff для файлов , activate был успешным swap_deactivate Объект swap _ Вызывается для чтения ици записи страниц подкачки , swap_rw 9.6. где когда установлен SWP_FS_OPS File Файловый объект представляет собой файл, открытый процессом. Cтpyктy­ pafile_ operations описывает, как VFS может манипулировать открытым фай­ лом. Содержимое структуры: struct file_operations struct module *owner; loff_t (*llseek) (struct file * , loff_t, int); ssize t (*read) (struct file *, char user * , size t , loff_t *) ; ssize t (*write) (struct file * , const char _user * , size_t , loff_t *); ssize t (*read_iter) (struct kiocb * , struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *) ; int (*iopoll) (struct kiocb *kiocb , bool spin) ; int (*iterate) (struct· file * , struct dir context *); int (*iterate_shared) (struct file * , struct dir_context *); _ poll t (*poll) (struct file * , struct poll_taЫe_struct *) ; long (*unlocked_ioctl) (struct file * , unsigned int , unsigned long) ; long (*compat ioctl) (struct file * , unsigned int , unsigned long) ; int (*mmap) (struct file *, struct vm_ area struct *) ; int (*open) (struct inode *, struct file *) ; int (*flush) (struct file * , fl_owner_ t id) ; int (*release) (struct inode * , struct file *) ; . ... -- -- -- --- -- -- -- . . . . . . . -- .. ----. --- . . . . . --- ....... --- . . . . . . . . . --- ... ---- . . . . . . _ ,
1 J1ава ') Фа~i . юв:ш t·11c1t·,i:111 s1 . 11ю rlinux _________ __. ______ _ int (*fs ync) (str uct file * , loff_t , loff_t , int datasync) ; int (*fasync) (int , struct file * , int) ; int (*lock) (struct file *, int , struct file lock *); ssize t (*sendpage) (struct fi le * , struct page * , int , size t , loff t *, int) ; unsigned long (* get_unmapped area) (struct file * , unsigned long , unsigned long , unsigned long , uns i gned long) ; int (*check_flags) (int); int (*flock ) (str uct file * , int , struct file lock *); ssize_t (*splice_write) (struct pipe_inode info * , struct file * , loff_t * , size_t , unsigned int); ssize_t (*splice_read) (struct file * , loff_t * , struct pipe_inode_info * , size_t , unsigned int) ; int· (*setlease) (struc t file *, long , struct file_lock ** , vo id **) ; long (*fallocate) (struct file *file , int mode , loff_t offset , loff_t len) ; void ( * show fdinf о) ( struct seq_file *m , struct file * f) ; #ifndef CONFIG ММU unsigned (* mmap capaЬilities ) (struct file *); #endif ssize t (*copy_f!le_range) (struct file * , loff_ t , struct file * , loff_t , size_t , unsigned int) ; loff t (* remap_f!le range) (st r uct file *file_ in , loff_t pos_in , struct file *file_out , l off_t pos_out , loff_t len , unsigned int remap_flags) ; int (*fadvise) ( struct file * , loff_t , loff_t , int) ; ); Описание членов структуры приведено в табл. 9.6. Все методы могут быть вызваны без блокировок . Таблица 9.6. Члены cmpyкmypыfi/e_operations Описание Метод llseek read read- iter • Вызывается , когда VFS необходимо переместить индекс позиции файла Вызывается read(2) и связанными системными вызовами Осуществляет асинхронное чтение с iov _iter в каче- стве назначения ·-·-·--·--·-·-·-----·--- · ----·---··----··-······ -------·-·--·---··-------··--·---- -IZ!ZI
Я . tро Liпux write write- iter iopoll iterate ....................... Вызывается write(2) 1 Используется для асинхронной записи с aio нужно опросить iocbs HIPRI iov_iter завершение на Вызывается, когда VFS необходимо прочитать со- держимое каталога Вызывается , когда iterate- shared и связанными системными вызовами Вызывается , когда n.iпux VFS необходимо прочитать со- держимое каталога, когда файловая система поддерживает параллельные итераторы каталогов Вызывается VFS, когда процесс хочет проверить, есть ли активность в этом файле, и (необязательно) poll перейти в спящий режим, пока не будет активно- сти. Вызывается системными вызовами select(2) и poll(2) Вызывается системным вызовом compat_ioёt/ ioctl(2), когда 32-битные системные вызовы используется на 64-битных ядрах ттар Вызывается системным вызовом Вызывается VFS, mmap(2) когда индексный дескриптор должен быть открыт. Когда VFS открывает файл, он создает новый "файл структуры" . Затем он вызывает метод ореп для вновь выделенной файловой структурь1. Вы можете подумать, что метод ореп ореп действительно относится к tions, struct inode_opera- и вы можете быть правы . Я думаю, что это сделано так, потому что это упрощает реализацию файловых систем. Метод open() -: хорошее место private_ data в файловой для инициализации члена структуре, если вы хотите указать на структуру устройства ., .....................................................................................
n.1пux ................. . jl.ush release fsync 1 1а11а 9. Фаii.ю11:н1 t·11e1t·ш111 s1 . 11ю Вызывается системным вызовом close(2) для Вызывается , когда закрывается последняя ссылка на открытый файл Вызывается системным вызовом Вызывается системным вызовом fasync очист- ки файла fsync(2) fcntl(2), когда для файла включен асинхронный (неблокирующий) режим lock get_ unmapped_ area check_fiags jl.ock Вызывается системным вызовом fcntl(2) для F_ GETLK, F_ SETLK и F_ SETLKW Вызывается системным вызовом Вызывается системным вызовом команд mmap(2) fcntl(2) для коман- дыF_SETFL Вызывается системным вызовом flock(2) ! Вызывается splice_ write VFS для объединения данных из кана- ла в файл. Этот метод используется системным вы- зовом Вызывается splice_read VFS для объединения данных из файла в канал. Этот метод используется системным вы- зовом . setlease splice(2) Вызывается VFS splice(2) для установки или освобождения аренды блокировки файла. Реализации должны вызывать setlease generic_setlease для записи или inode после ее установки удаления аренды в fallocate • Вызывается VFS для предварительного выделения блоков или пробивания отверстий ... .. ..... -- -. ----- .... -- -- ......... ···- --- -- --- --- --- ---- -............... -- -..... . . .
_____ . _________________ n.iпux И 1ро J,i1111, сору__file _range Вызывается системным вызовом сору_file _range(2) Вызывается системным вызовом и FICLONERANGE, FICLONE ioctl(2) для команд FIDEDUPERANGE для переназначения диапазонов файлов. Реализация должна переназначить байты len в pos_in исходноpos_out. Реализации вызовы, передающие len == го файла в файл назначения в должны обрабатывать О; это означает "переназначить в конец исходно- го файла" . Возвращаемое значение должно быть числом переназначенных байтов или обычным отрицательным кодом ошибки, если ошибки про- remap__file_range изошли до того , как какие-либо байты были переназначены. Параметр remap_fiags принимает флаги REMAP _FILE_ *. Если REMAP_FILE_DEDUP установлен, то реализация должна переназначать только в том случае, если запрошенные диапазоны файлов имеют идентичное содержимое . Если FILE_ CAN_ SHORTEN установлен , REMAP_ вызывающая сторона не возражает против того , 'Побы реализация сокращала длину запроса для удовлетворения требований выравнивания или EOF (или по любой другой причине) fadvise Вызывается системным вызовом fadvise64() Обратите внимание, что файловые операции реализуются конкретной фай­ ловой системой , в которой находится индексный дескриптор. При открытии узла устройства (специального символьного или блочного) большинство файловых систем вызывают специальные процедуры поддержки в VFS, ко­ торые находят необходимую информацию о драйвере устройства. Эти под­ программы поддержки заменяют файловые операции файловой системы операциями для драйвера устройства, а затем продолжают вызывать новый метод open() для файла . Именно так открытие файла устройства в файловой системе в конечном итоге приводит к вызову метода ства. open() драйвера устрой­ • . ... -- . - -- ............... ··- ... --- - - - . - - .. -- .......... -- . -- ........... -- .. - ........ , •
1 n.inux .................. . 9.7. Кэш записей каталога 9.7.1. Структура Структура dentry_ operations VFS (dcache) dentry_operations описывает, как файловая система может пере­ грузить стандартные операции ся областью 1 , 1ва () Фаii . 111вю1 с11t·н·,1а 11 я , 11ю dentry. Записи Dentries и dcache являют­ и отдельных реализаций файловой системы. Драйверы устройств здесь ни причем. Этим методам может быть присвоено значение NULL, так как они либо являются необязательными , либо значение по умолчанию, Начиная с ядра 2.6.22 VFS использует (по текущую версию ядра), определены следующие члены: struct dentry_operations { int (*d_revalidate) (struct dentry, * , unsigned int) ; int (*d_weak_revalidate) (strµct dentry * , unsigned int) ; int (*d_hash) (const struct dentry * , struct qstr *) ; int (*d_compare) (const struct dentry * , unsigned int , const char *, const struct qstr *); int (*d_delete) (const struct dentry *) ; int (*d_init) (struct dentry *) ; void (*d_release) (struct dentry *); void (*d_iput) (struct dentry * , struct in ode *); char * (*d_dname) (struct dentry * , ch ar * , int) ; struct vfsmount * (* d automount ) (struct path *); int (*d_manage) (const struc t path * , bool) ; struct dentry * (*d real ) (stru c t d e ntry * , const struct inode *); }; Описание членов структуры приводится в табл. • 9.7 . ······························--···-··········-··················· · · · ······ -· · ·- · ·IZiil
И , 1р11 l.itlll\ Таблица 9. 7. ....................... n.1nux Описание членов структуры dentry_operations Описание Метод Вызывается, когда dentry. необходимо перепроверить VFS Это вызывается всякий раз, когда поиск имени находит dentry в Большинство локальных фай- dcache. ловых систем оставляют это значение равным потому что все их d- revalidate dentries в NULL, dcache действительны. Сетевые файловые системы отличаются тем, что чтото может измениться на сервере без ведома клиента. Эта функция должна возвращать положительное значение, если dentry все еще действительна, и ноль (если недействительна) или отрицательный код ошибки, если это не так Вызывается, когда VFS необходимо повторно прове- рить "перепрыгнувший" обход пути dentry. Это вызывается, когда заканчивается на dentry, который не был получен путем поиска в родительском каталоге. Это включает в себя"/","." и" .. ", а также символические ссылки в стиле - weak- revalidate procfs и обход точки монтирования. В этом случае нас заботит не столько правильность dentry, сколько то, что индекс по-прежнему действи- телен. Как и в случае с d_revalidate, большинство локальных файловых систем установит его в поскольку их записи в dcache NULL, всегда действительны. Эта функция имеет ту же семантику кода возврата, что и d- revalidate Вызывается, когда таблицу. Первый d- hash VFS добавляет dentry в хешdentry, переданный в d_hash, являет- ся родительским каталогом, в который должно быть хешировано имя. Те же правила блокировки и синхронизации, что и в d_compare, в отношении того, что безопасно для разыменования и т.д. • . . . . --------------.-------------~ -------------- ------ -------------------------------.
1 1 ,1 11а n.1nux ................. . ' ) Фаii . 11111.ш r11rн• ,ia 11 i1, 1po Вызывается для сравнения имени dentry с заданным dentry является родителем сравниdentry, второй-дочерним dentry. Параме- именем. Первый ваемого тры !еп и пате являются свойствами сравниваемого это имя, с которым его нужно сравнить. dentry. qstr d_compare Должен быть постоянным и идемпотентным, не должен по возможности блокироваться и не должен сохраняться в dentry. Не следует без особой осторож- ности разыменовывать указатели за пределами (например, не следует использовать dentry d_parent, d_inode, d_name) Вызывается, когда последняя ссылка на d- delete брасывается, и Возвращает dcache решает, 1 для немедленного удаления или О для кэширования d- init d- release dentry от- кэшировать ее или нет. dentry Вызывается при выделении dentry Вызывается, когда dentry действительно освобожда~ ется Вызывается , когда dentry теряет свой inode (непосред- ственно перед его освобождением) . По умолчанию , d_iput когда это значение равно NULL, VFS вызывает iput(). Если вы определяете этот метод, вы должны сами вы- звать • iput() .• --- --•-- --- ----- ----- ---- --- ---- -- -. --- --- -- -- --- --- -- ----- -------- -- ---- ---- ---- -
Я11pol,inux ....................... n..inux Вызы вается, когда должно быть сгенерировано имя пути к dentry. Полезно для некоторых псевдо файло­ (sockfs, pipefs, ... ) для задержки создания вых систем пути. Реальные файловые системы, вероятно, не хотят его использовать, потому что их dentries присутствуют в глобальном хэше dcache, поэтому их хэш должен быть инвариантом. Поскольку блокировка не удержи­ вается, функция d_dname() не должна пытаться моди­ фицировать сам dentry, если только не используется соответствующая безопасность SMP. ВНИМАНИЕ: логика d_path() довольно сложна. Правильный способ вернуть , например, "Hello" - поместить его в d dnam e конец буфера и вернуть указатель на первый символ. Для этого предусмотрена вспомогательная функция dynamic _ dname(). Пример: static char *pipefs_dname (stru ct dentry *dent , char *buffer , int buflen ) { return dynamic_dnarre (dentry, buffer, buflen, "pipe : [%lu] ", dentry- >d_inode- >i_ino ) ; Вызы вается , когда необходимо пройти через автомон­ тирование dent,y (необязательно) . Это должно создать новую запись монтирования VFS и вернуть запись вызывающей стороне. Вызывающий объект получает параметр пути, задающий каталог автомонтирования для описания цели автомонтирования и родительскую d automount запись монтирования VFS для обеспечения наследуе­ мых параметров монтирования. Значение NULL воз­ вращается , если кому-то другому удалось выполнить автомонтирование первым. Если создание vfsmount не удалось, должен быть возвращен код ошибки. Если возвращается -EISDIR, то каталог будет рассматри­ ваться, как обычный каталог и возвращен в для продолжения обхода pathwa\k
I J 1aнa t'.l1nux .................. . 9. Файтшаs, с11сн· 1ш111 sщро Вызывается, чтобы позволить файловой системе управлять переходом от позволяет dentry (необязательно). Это autofs, например, задерживать клиентов, позволяя демону автомонтирования пройти мимо и построить там поддерево. Значение О возвращается, чтобы продолжить вызывающий процесс . Значение d_manage -EISDIR возвращается, чтобы сказать pathwalk ис- пользовать этот каталог как обычный каталог и игнорировать все, что смонтировано в нем, и не проверять флаг автомонтирования . Любой другой код ошибки полностью прервет путь Файловые системы типа метод для возврата d- real overlay/union реализуют этот одного из базовых dentry, скрытых оверлеем Помните , что каждый dentry также хеш-список дочерних имеет указатель на его родительский dentry. dentry, а Дочерние записи в основном похожи на файлы в каталоге. 9.7.2. API кэша записей каталогов Определен ряд функций, которые позволяют файловой системе манипули­ ровать dentries: • dget - позволяет открыть новый дескриптор для существующего dentry (увеличивает счетчик использования). • dput - закрывает дескриптор для вания, член i_ count). dentry (уменьшает счетчик использо­ Если счетчик использования падает до О, а все еще находится в хэше своего родителя , вызывается метод dentry "d_delete", чтобы проверить , следует ли его кэшировать. Если его не нужно кэши­ ровать или если dentry не хешируется , он удаляется. В противном случае кэшированные dentгy помещаются в список • LRU для восстановления при нехватке памяти. • ··················································································8 1
Я ; tро 1,iщах ...... . ................ n.1nux • d_drop - удаляет dentry из списка хэшей его родителей. Последующий вызов dput() освободит dentry, если счетчик использования упадет до О . • d_delete - удаляет dentry. Если нет других открытых ссылок на dentry, то dentry превращается в отрицательную dentry (вызывается метод d_iput()). Если есть другие ссылки, то вызывается d_drop(). • d_add вызвать позволяет добавить dentry в список хэшей его родителей, а затем d_instantiate(). dentry в список хэшей псевдонимов для "d_inode". Член "i_count" в структуре inode должен быть установлен/увеличен. Если указатель inode равен NULL, dentry называется "отрицателыюй dentry". Данная функ­ • d_instantiate - позволяет добавить индексного дескриптора и обновить элемент ция обычно вызывается, когда создается индексный дескриптор для су­ ществующей отрицательной • d_lookup - dentry. поиск dentry по данным его родителя и компонента имени пути. Он ищет дочерний элемент с заданным именем из хеш-таблицы dcache. Если он найден, счетчик ссылок увеличивается и возвращается dentry. Вызывающий должен использовать dput() для освобождения dentry после завершения его использования . ....................................................................................
Глава 10. Псевдофайловые системы
Я , 1ро l,inux 10.1. . ...................... t')_lnux Назначение Псевдофайловые системы sysfs (каталог /sys) и proc (каталог /proc) исполь­ зуются для настройки системы и получения различной информации о системе и процессах. Свое название псевдофайловые системы получили из­ за того, что они работают на уровне виртуалыюй файловой системы. В ито­ ге оба эти средства (назовем их так) для конечных пользователей выглядят как обычная файловая система каталог /proc. - вы можете зайти как в каталог /sys, так и в В обоих этих каталогах будут файлы, вы можете просмотреть эти файлы и даже изменить их содержимое. Содержимое многих файлов псевдофайловой системы /proc формируется "на лету". Обратите внимание на размер любого файла в каталоге /proc - он равен нулю, но если открыть файл, то информация в нем будет. Например, в · файле /proc/version находится информация о версии Монтирование файловых систем sysfs ях инициализации системы, или через Linux. и proc осуществляется или в сценари­ /etc/fstab. В последнем случае записи монтирования псевдофайловых систем выглядят так: • at·." .... "". --· ............................---· .. -·· ...... -................ "... "... .
. n.iпux __________________ _ / s ys / pr oc sysfs proc 10.2. sysfs proc 1 1 1ава I О. Пссвдофаii J 1овыс с11с I смы defaults defaults Псевд о файловая система о о о о sysjs Файловая система sysfs (каталог /sys) предоставляет пользователю инфор ­ Linux, об имеющихся в системе устройсп~ах и драйверах этих На рис . 10.1 представлено содержание катал ога /sys. В нем вы мацию о ядре устройств. найдете сл~дующие подкаталоги : • Ыосk - содержит каталоги для всех блочных устройств , которые есть в вашей системе в настоящее время. Здесь под устройством подразумевает­ ся наличие физического устройства и его драйвера . Если вы подключите внешний жесткий диск, то в каталоге /sys/devices появится новое устрой­ ство, но в каталоге /sys/Ыock оно появится только , если в системе есть драйвер для работы с этим устройством или же драйвер (модуль) встроен в само ядро. • bus - здесь находится список шин, которые поддерживает ваше ядро. Заглянув в этот каталог, вы обнаружите подкаталоги pci, pci_ express, scsi devices и drivers. В и т. д. В каждом из этих каталогов будут подкаталоги первом находится информация об устройствах , подключенных к данной шине, во втором • class - - информация о драйверах устройств. позволяет понять , как устройства формируются в классы . Для каж­ дого класса есть отдельный подкаталог в каталоге class. содержит дерево устройств ядра, точнее структуру файлов и ка­ • devices - талогов, которая полностью соответствует внутреннему дереву устройств ядра. • firmware - содержит интерфейсы, предназначенные для просмотра и ма- нипулирования finnwаrе-специфичными объектами и их параметрами . • fs - информация о файловых системах, которые поддерживает ваше ядро . • kernel - общая информация о ядре. • module - здесь вы найдете подкаталоги для каждого загруженного мо­ дуля ядра. Имя подкаталога соответствует имени модуля. В каждом из подкаталогов модулей вы найдете подкаталог parameters, содержащий специфичные для модуля параметры. , _--------.--.-----.-.---.. ---.-.----.... --.-.----..... ---.. -.... --.--... --_._----fJII
Ядро , Linux • power - А . ....................... t_J,.1nux позволяет управлять параметрами питания, а также переводить систему из одного состояния питания в другое. Далее будет показано несколько примеров . hlock bus class d- devices firmware fs kernel module power Рис. 10.1. Содержание катш~ога /sys Довольно интересен с практической точки зрения каталог файле state /sys/power. В находится состояние питания. Изменив должным образом со­ держимое этого файла, можно изменить состояние питания. Например, вот как можно перевести систему в ~остояние "Suspend to RAM", когда питание процессора отключается, но питание на память подается, благодаря чему ее содержимое не уничтожается: $ sudo echo - n mem > /sys/power/state •При желании можно отправить систему в состояние "Suspend to Disk", когда содержимое памяти будет записано на жесткий диск, пос_ле чего питание будет отключено: $ sudo echo - n disk > /sys/power/state 10.3. Псевдофайловая система proc Файловая система proc позволяет отправлять информацию ядру, модулям и процессам. Вы можете не только получать информацию о процессах, но из- • ....................................................................................
[ ~ 1ана r.linux ______ ___________ _ IО . Пссв, 10файловые с11с Iемы менять параметры ядра и системы "на лету" . Эта файловая система интерес­ на тем, что позволяет изменять такие параметры ядра, которые невозможно изменить другим способом, к тому же вносимые изменения вступают в силу сразу же. Некоторые файлы в /proc доступны только для чтения вы можете только - просмотреть их. А некоторые вы можете изменять , и эти изменения сразу же отразятся на работе системы. Просмотреть файлы из /proc можно любой программой для просмотра файлов, проще всего в консоли использовать ко­ манду ca t cat: /рrос/< н аз в ание ф айла> Записать информацию в файл можно с помощью команды echo, как уже было показано выше : sudo echo В каталоге " и нф орм ац ия " /proc > /рrос/< н азва н ие файла> очень много файлов и рассмотреть их все мы не сможем. Прежде, чем мы приступим к самым интересным с моей точки зрения фай­ лам, нужно понять, что означают каталоги с числами. Эти каталоги содержат информацию о запущеннь1х процессах. Итак, самые полезные информационные файлы: • /proc/cmdline - содержит параметры, переданные ядру при з агрузке. • /proc/cpuinfo - содержит информацию о процессоре , откройте этот файл , думаю , вам будет интересно . Кроме общей информации о процессоре вроде модели и частоты , здесь выводится точная частота , размер кэша и псевдорейтинг производительности , выраженный в ние BogoMIPS BogoMIPS. Значе­ показывает "сколько миллионов р а'з в секунду компьютер может абсолютно ничего не делать" . Способ измерения производител ь­ ности пусть и не самый удачный , но от него до сих пор не отказались , а "на дворе" уже 3-я версия ядра. • /proc/devices - список устройств . • /proc/filesystems вых систем . • полный список поддерживаемых вашим ядром файло­ .------------..... -... -.... -.... -... - - .. --- .. -... - -. -- -... --.. --... -... --... -... -. . . .
Ядро ___________________ __ __n.iпux l.inux • /proc/interrupts - информация по прерываниям. информация о портах ввода/вывода . • /proc/ioports - • /proc/meminfo - полная информация об использовании оперативной па~ мяти. Как по мне , вывод этого файла более понятен и удобен, чем вывод командыfrее. • /proc/mounts • /proc/modules • /proc/swaps - /proc список загруженных модулей и их параметры. содержит список активных разделов и файлов подкачки. • /proc/version - Используя содержит список подмонтированных файловых систем. здесь находится версия ядра. можно не только получить информацию о системе, но и 'из­ менить ее. Например, в файлах domainname и /proc/sys/kemel/hostname /proc/sys/kemel/ содержится информация об имени компьютера и домена. Вы MOfI<eтe не только просмотреть, но и изменить содержимое этих файлов, из­ менив , соответственно , имя узла и имя домена. Хотя практика изменения доменных имен через /proc/sys практикуется не часто , никто не мешает вам это сделать : sudo echo " server " > / proc / sys / kernel/ho stname sudo echo " example . com " > / proc / sys / kernel / domainn a me Файл /proc/sys/kemel/ctrl-alt-del позволяет регулировать тип перезагрузки системы при нажатии комбинации клавиш Ctrl+Alt+Del. По умолчанию в этом файле содержится значение О, что означает так называемую "мягкую перезагрузку" при нажатии Reset (soft reboot). Если же вы внесете в этот файл значение 1, то Ctrl+Alt+Del эффект будет такой же , как при нажатии кнопки на корпусе компьютера: sudo e cho " l " > / proc / sys / kernel /c trl - alt - del Файл /proc/sys/kemel/printk позволяет задать, какие сообщения ядра будут выведены на консоль , а какие - попадут в журнал демона нию в этом файле содержатся значения 4 4 1 7. syslog. По умолча­ Сообщения с приоритетом ниже (первая четверка) будут выводиться на консоль. Вторая четверка - 4и это • 1111-----... -.. -.-.-.---.--... -.-.--.---.----------.-.----.. ----.-.------.---.----..... ' •
r.linux _____ _____ _____ ____ \ 'лава I О . flсевдофайловые системы уровень приоритета по умолчанию. Если для сообщения не задан уровень приоритета, то считается, что его приоритет будет равен 4. Третье значение определяет номер самого максимального приоритета. Последнее значение - э то уровень приоритета по умолч анию для пер вого значения. В большинстве случаев изменяют только пер вое значение , позволяющее определить, будет ли сообщения с указанным уровнем приоритета выво­ диться на консоль или нет. Остальные параметры оставляют без изменения. В файле /proc/sys/net/core/netdev_ max_ backlog содержится максимал ьное число пакетов в очереди. Значение по умолчанию Ф айл /proc/sys/fs/file-max - 1000. позволяет изменить максимальное количество за­ головков файло в , которое может быть одновременно открыто . Другими сло­ вами, этот файл задает, сколько одновременно может быть открыто файлов. Значение по умолчанию для ядра 3.16 и файловой системы Ьtrfs - 73054. Чтобы сохранить внесенные "на лету" изменения , и чтобы их не пришлось снова вводить при следующей перезагрузке сервера, нужно отредактировать файл /etc/sysctl.conf. Представим, что вы изменили значение из файла /proc/ sys/fs/file -max. Тогда в файл /etc/sysctl.conf нужно добавить строку: fs . file - max 16 384 Принцип прост: /proc/sys/ отбрасывается совсем , а в оставш ейся строке все слеши заменяются точкам и . Само же з начен ие указывается че ре з знак равенства. Если нужно указать несколько з начен ий, то они указываются че­ рез пробел . • .-- ---- . ---- ... --- ---- . -- . -- -- ---- . --- . -- . --- -. -- ---. --- -. -- . -- ---. ---- -.. -- . - . . . . . . .
Глава .. 11. . Пользователи и группы
Ядро [,inux ....................... n..inux 11.1. Введени е в учетные з аписи Для того, чтобы эффективнее работать с ядром Linux Linux, нужно хорошо раз­ бираться в особенностях учетных записей и группах пользователей Linux. I Операционная система Linux поддерживает регистрацию и одновременную работу множества пользователей. Обратите внимание: именно одновремен­ ную работу. Раньше, еще во времена UNIX, были компьютеры, к которым подключалось несколько мониторов и клавиатур. Каждый комплект монитор + клавиатура назывался терминалом и представлял собой от­ дельное рабочее место пользователя. Пользователь входил в систему, а его рабочее место в системе отображалось как ttyN, где N- номер рабочего места. Сегодня такие компьютеры уже более не востребованы, их вытеснили персо­ нальные компьютеры, которые и стали называться персональными, посколь­ ку предполагают подключение только одного рабочего места. Мониторов можно подключить несколько, а устройство ввода - клавиатура будет одна. Но даже на таких компьютерах возможна одновременная работа несколь­ ких пользователей. Например , вы можете войти в систему как обычно - посредством графического интерфейса. Другие пользователи смогут войти через ssh .. или FTP. И все вы будете работать с системой одновременно. SSН­ пользователи смогут выполнять команды и получать результат их выполне­ ния, FТР-пользователи - обмениваться с вашим компьютером файлами . • . . . -... -........ -... •. -.. -... --.... -....... -.... -........ -... -................. -.. .
I J ia в a n.inux _________________ _ 11 . Пользователи и гру1111ы Все учетные записи можно разделить на три вида: учетные записи обычных пользователей , учетные записи системных служб и учетная запись учетными записями обычных пользователей все ясно - root. С они имеют право входить в систему разными способами (если тот или иной способ не запре­ щен настройками системы), для них определен домашний каталог (обычно /hоmе/<имя_пользователя>), пароль и командная оболочка (как правило, в последнее время используется /Ьin/Ьash). Права обычных учетных записей: • Право на вход в систему по умолчанию обычный пользователь мо­ - жет войти в систему самыми разными способами , если это не ограничено настройками системы (например, модулями РАМ) . Пользователь может войти локально - через консоль или в графическом режиме через дисплей-менеджер вроде gdm. Также никто не запрещает (опять-таки по умолчанию) удаленный вход, например, по SSH или если на FTP, компьютере , в который осуществляется вход, установлены соответству­ ющие службы. • Право на запуск программ, не требующих для своего выполнения прав root - как правило, такие программы находятся в каталогах /Ьin и usr/Ьin. А вот из каталога /sbin / запустить программу может только супер­ пользователь. Программы , действие которых распространяется на всю систему, например программы изменения сетевых интерфейсов , программы разметки диска, находятся в каталоге /sbin (super-bin). Что­ бы запустить эти программы , пользователю нужно получить полномочия root. • О том, как это сделать, будет сказано в следующем разделе . Обычный пользователь может создавать, удалять, читать, изменять, запускать, устанавливать права и выполнять другие операции над фай­ лами, которые находятся в его домашнем каталоге. Как правило , это ка­ талог /hоmе/<имя _ пользователя> . Хотя администратор может назначить пользователю любой другой каталог, хоть /users/Ьagira, как правило, этого никто не делает. Каталог /home может находиться физически на одном разделе, что и корневая файловая система, а может находиться и на дру­ гом разделе и даже на другом диске. На крупных серверах, как правило , под • /home отводят целый диск или даже создают RАID-массивы дисков. Право на чтение файлов - обычный пользователь может читать боль­ шую часть файлов за пределами домашнего каталога. Исключения раз­ ве что составляют домашние каталоги ' других пользователей (если эти '-- другие пользователи явно не разрешили этому пользователю читать их -. - · - . · · - . . · - ... · - · . . . . . . --· . . . . . . . . . . . . . . . -- ·---. . . - - · · · · - · . . . . . . . . . . . - · . . - . . --
И . 11111 l ,illll\ ...................... t.\.1nux файлы) и некоторые файлы/каталоги в могут читать все пользователи, а вот • /etc. Например, файл /etc/shadow - файл /etc/passwd только root. Пользователь не имеет право вносить изменения в конфигурацию всей_ системы , то есть устанавливать программы, изменять глобальные настройки устройств, параметры ядра, параметры загрузчика и т.д. • Пользователь имеет право изменить свои пользовательские параме­ тры, например, обои рабочего стола, некоторые переменные окружения , которые будут влиять только на его работу и т.д. • Право на изм~нение своего пароля, но обычный пользователь не имеет право изменять пароль других пользователей. Учетные записи системных служб не имеют право входить в систему. Для них не задан ни пароль, ни домашний каталог, а в качестве оболочки исполь­ зуется /Ьin/true или /Ьin/false - чтобы пользователь , используя учетную за­ пись службы, не мог войти в систему через консоль. От имени таких учетных записей выполняются различные службы, например, от имени пользователя www-data выполняется Display Manager и т.д. Пользователь root - веб-сервер, gdm - учетная запись для GNOME пользователь с максимальными правами, он может делать все: • Право на изменение любого файла root - может читать, записывать, удалять любые файлы, в том числе и файлы в домашних каталогах других пользователей. • Право на изменение конфигурации системы - пользователь root мо­ жет изменять конфигурацию системы посредством редактирования фай­ лов в каталоге • /etc, /proc, запуска конфигураторов системы . Право на запуск любых программ - root может запустить любую программу, в каком бы каталоге она ни находилась. • Право на создание, удаление, изменение (в том числе изменение паро­ ля) других учетных записей. • Право на установку и удаление программ. • . . ................ . ........ .. . . . ...... .. .. .. .. .... ............ . ........ .. ..... . . . . . ..
11 , 111.1 11.110.11,юкан-. 111111р~1111ы r.l1nux . ................ . Власть пользователя неограниченна. Так было до определенного мо­ root мента, пока не появились системы принудительного контроля доступа вроде SELinux, LIDS, Tomoyo, которые могут ограничить даже самого root. Вот SELinux, LIDS, Tomoyo и другие подобные с~стемы только беда в том, что по умолчанию неактивны или даже не установлены, поэтому пока их не ак­ тивировать, пользователь root будет все равно самым главным. Примечание. Напомним, что когда у вас привилегии пользова­ теля лом 11.2. root, #, приглашение командной строки заканчивается симво­ а когда вы работаете как обычный пользователь Получение полномочий Самый простой способ получить права - $. root root - это войти как при входе в систему вы указываете имя пользователя root root. То есть и пароль , указан­ ный при установке. Проблема в том, что не во всех дистрибутивах этот трюк сработает. Учитывая всю опасность, которую несет использование учетной записи root, во многих дистрибутивах учетная запись root отключена, а вход root ограничен самыми разными способами. Включать учетную запись root не . рекомендуется - ведь злоумышленник знает, что учетка root есть как везде и ему не придется угадывать имя пользователя, останется только по­ добрать пароль root. root. А так вы исключаете даже саму возможность входа как Тем более права root можно получить другим образом, о котором мы nоговорим далее. А пока рассмотрим способы блокировки входа (кроме отключения учетной записи) Часто вход как root. root ограничен на уровне менеджера дисплея. В дистрибути­ вах, где используется графическая среда КDЕ и менеджер экрана КDМ (К Display Manager), нужно отредактировать файл /etc/alternatives/kdm4-config. В нем нужно найти директиву AllowRootLogin и присвоить ей значение true, чем вы разрешите вход как root в графическом режиме. При использовании GDM (Gnome Display Manager) вход как root ограничен GDM, а столько РАМ-модулями. Нужно открыть /etc/pam.d/gdm-password и найти строку, отвечающую за запрет вхо­ да как root. Она может выглядеть, например, так: не столько конфигурацией самого auth required pam_succeed_if.so user ! = root quiet • ·· ····· ··· ········································································ -
Я ; {ро IJnux ....................... n..inux Некоторые дистрибутивы разрешают заходить как гооt даже в графическом режиме. Просто они отображают предупреждение о том, что работать как root небезопасно . В Linux Пример такого дистрибути ва используется оболочка нятся в каталоге /etc/fly. Fly, - CentOS. конфигурационные файлы которой хра­ Это собственная разработка, которую не встретить в других дистрибутивах. За графический вход в систему отвечает fly-dm (Fly Display Manager), конфигурационные файлы которого находятся в ката­ /etc/Xl 1/fly-dm. Основной файл конфигурации - fly-dmrc . Самое ин­ тересное, что вход как root в Linux по умолчанию разрешен параметр Allow RootLogin у~тановлен в true (рис. 11.1 ). Поэтому если вам очень силь­ логе но хочется войти как гооt в графический режим , вы можете это сделать , но сначала вам нужно изменить пароль самого пользователя root - как это сде­ лать, будет показано далее. Пока нужно отметить, что вход как графическом , что в настольном режиме - root что в очень опасная штука. Поэтому если вы за безопасность, выключите данный параметр (значение/а/sе), а для временного получения полномочий root используйте команду sudo (будет показано далее) . Рис. 11.1. Файл коиф11гурац1111ftу-dтrс • . .. ... . . ..... .. . ... .. .. . ........ .. . . . .. . . . . ... . . . .. . . . ....... .. . . . . ... . . . .. . . . . . . . . .
1 1 1ав а ft.inux ................. . 11 . ПОJ1ыова, еJ Ш и I ру1111ы Настоятельно рекомендуется работать в системе как обычный пользователь, а максимальные права получать только тогда, когда они вам действительно нужны. Например, когда понадобится запустить какую-то программу, требу­ ющую права root. При этом вам особо ничего не придется делать, кроме как ввести пароль. Рассмотрим пример. Вы установили, например создали учетную запись mark Astra Linux, и при установке и задали пароль. По умолчанию инсталлятор создает первую учетную запись так, что она вносится в группу sudo root. Други­ является root, членам этой группы можно выполнять команды с привилегиями ми словами, созд~нный во время установки пользователь уже только с некоторыми оговорками. Настройки , позволяющие группе хранятся в файле /etc/sudoers. sudo выполнять команды от имени root, В этом файле указываются все учетные записи, имеющие право выполнять административные задачи. Когда вы по­ пытаетесь выполнить одну из таких задач, например, добавить нового поль­ зователя, графический интерфейс автоматически запросит у вас ваш пароль. Аналогично, когда вы будете пытаться запустить командную оболочку (ко­ манда root. Это будет не пароль root, а ваш пароль, то есть пароль пользователя mark (рис. 11.2). Ему разрешено выполнять адми­ нистративные задачи, просто система пытается убедиться, что вы - это вы, sudo bash) с правами а не некто, кто оказался за вашим компьютером во время вашего отсутствия. Рис. • 11.2. Запуск командной оболочки с правами но ввести пароль пользователя root- ко.манда sudo bash. mark, а не root! Нуж­ .---- ----- -- ---- ................... -................. --........................... . . . •
я , .ро (,iпux ....................... n..inux Когда же вам нужна командная строка с правами root, не обязательно даже переключаться в консоль. Достаточно открыть терминал и ввести команду su. Она попросит вас ввести пароль терминал с правами root. вводить после ввода команды няться с правами После ввода пароля вы получаете root. Это означает, что все команды, которые вы будете su и успешной аутентификации, будут, выпол­ root. Примечание. Если учетная запись жете использовать команду парол~ Когда вы - root, sudo, то вы не смо­ а вы его не знаете. единственный администратор, команда ант. Но когда администраторов несколько, ку пароль root отключена, так как она предполагает ввод root su - идеальный вари­ команда su - не выход, посколь­ нужно будет сообщить всем остальным администраторам. Если потом возникнет нестандартная ситуация, выяснить, кто виноват, будет сложнее. На этот случай у пользователя root могут быть доверенные лица. Это может быть помощник администратора, его заместитель называйте, как хотите. Есть лица, которым разрешено получать права Такие лица вносятся в файл /etc/sudoers ( если вам не sudo (так правильнее). root. лень прописывать каждого отдельно) либо в группу ... Рис. - 11.3. -- Редактирование файла -- /etc/sudoers • ----- ---- -.. ---- ---- -------------------- . . . . . . . ·- ....... ... ---. ----- -- .. -----
l . 1ава 11 . t\.inux. _............... . Редактировать файл По. 1ыо~щ1е. 111 и I р~ 1111ы можно только через команду /etc/sudoers visudo (рис. 11.3): expo rt EDITOR=nan o sudo visudo Первая команда устанавливает переменную окружения EDIТOR, задающую удобный текстовый редактор, который будет использован для /etc/sudoers. Вторая команда вызывает утилиту для редактирования файла /etc/sudoers. Представим, чт.о у нас есть пользователь делать все, что можно пользователю sudoers bagira, которому нужно разрешить root. Для этого нужно добавить в /etc/ запись вида: bagira ALL=(ALL:ALL) ALL Можно также добавить запись : %s udo ALL= (ALL: ALL) ALL Она означает, что членам группы пользователю вить в группу root. Тогда sudo (далее sudo можно делать все , что можно делать всех администраторов-помощников нужно доба­ будет показано, как это сделать). Сохраните файл и выйдите из редактора. Войдите как пользователь, которо­ му вы предоставили право sudo. В нашем случае-это пользователь Далее введите команду, которая требует прав sudo root через bagira. команду sudo: < к о манда > Например: sudo bash , Обратите внимание: система запрашивает пароль пользователя, а не пароль , root. Пользователь указывает свой пароль, а система знает, что ему разрешено получать права root. В итоге наши помощники не знают пароль -............ ---. ------· -. --. ----. -----------.. ---·- ---------------.. ----. ------ _
Я J tpo root [,inux ••••••••••••••••••••••• и смогут выполнять определенные действия с пр авами root rtiпux под своим именем. Как правило, вам не нужно вообще редактировать файл денная информация о его формате - /etc/sudoers. только для общего развития. На прак­ тике вам нужно просто добавить пользователя в группу появилась возможность получать права sudo usermod -а Приве­ sudo, чтобы у него root: - G sudo bagira Данная команда изменяет группу для пользователя список групп пользователя группу Контролировать получение прав bagira , добавляя (-а) в (-G) sudo. sudo можно командой 1 : # tail /var/log/auth . log I grep sudo Посмотрите на рис . mark 11.4. Для примера , 6 июля 2022 года в 7.16 пользователь sudo для выполнения команды bash. То только попытки использования sudo, но и пытался выполнить коман ду есть в журнале отображаются не журналируются даже вводимые польз овател ями команды. Рис. 1 11.4. Журнал аутентификации aut/1.log В некото ры х дист р ибут ивах журн ал аутентификации называется secure, а не auth.log. • . . ..-- --- --- ----- ------- --- -- -- ---- --- -- -- --------- -- ------ --- ---- -. -. --- --- . ------ -. •
1нава 11 . r.linux -················· llш11,т1ш 11.'J Ш 11 1 ру1111м Если вам нужно получить некоторый аналог команды su, чтобы вы могли вводить сразу неограниченное количество команд с максимальными права­ ми без приставки sudo, используйте следующий трюк мальными правами оболочку bash. Все - запустите с макси­ команды , вводимые в этой оболочке, будут выполнены с максимальными правами: sudo bash Закрыть такой сеанс можно командой exit . . Прежде чем перейти к следующему разде!Jу, разберемся, как сменить пароль пользователя root. Для этого нужно просто задать пароль: su d o passwd r oo t Сначала нужно ввести ваш пароль, затем новый пароль для - root, после этого подтвердить пароль. После этого вы сможете войти в систему как root в консоли. Для входа в графическом режиме нужно редактировать файл, отно­ сящийся к РАМ, как было сказано ранее. Отметим, что активация пользова­ теля правильнее использовать коман­ ду root - занятие небезопасное, гораздо sudo. На личном компьютере еще такое сервере такое делать воспрещено. мероприятие допускается, но на 11.3. Уп равление учетными записями пользователей 11.3.1. Создание учетной записи пользователя Создать новую учетную запись пользователя можно командой adduser. Пример: sudo adduser evg • .-- . ---------- -------- --. ------ ------------------------------------------. ------ -.. . .
Ядро Linux _______ _____ ___ ___ __ __ _n..inux В большинстве случаев adduser просто добавляет в файл учетную запись поль зо вателя . Но в Linux /etc/passwd данная коман да запрашивает не только имя пользователя (которое передается команде в качестве пер в ого параметра), но и пароль пользовател я. Также есть во зм ожность ввести дополнительную информацию о пользователе, если есть такая необхо­ димость (см. рис . 11.5). Рис. 11.5. Создание нового пол ьзователя в Linux Если при создании парол ь задан неверно (вы задали слишком простой или слишком сложный пароль и хотите его изменить), можно сменить пароль с помощью команд ы passwd: su d o p ass wd п ользователя имя Напомню, что для добавления учец-юй записи пользователя нужны права root, который пq_льзо вател ь может получить через сен в /etc/sudoers В Linux su или sudo, если он вне­ и ему разрешена операция добавления пользователя . есть также графический конфигуратор и создать пользо вателя мож­ но не только с помощью команды adduser. Чтоб ы открыть графический кон­ фигуратор и создать пользователя, выполните следующие действия : • 1!!1- ------------------------------------ ---------- ----------------------------------- ·
1j 1 ава 11 . n..inux ................. . flш1ыова I с. 111 11 1 ру1111ы 1. Откройте Панель управления. 2. Перейдите в раздел Безопасность и запустите Управление политикой безопасности. Перейдите в раздел пользоват~ля и нажмите кнопку+ на панели инстру­ 3. ментов . Заполните информацию о пользователе и нажмите зеленую галку на па­ 4. нели инструментов для сохранения пользователя (рис . 11.6). Eil PIOOч,oA(TM • ~ otюP)'A,Qtl.OИ""" Груnпw Рис. ll.6. :Swнtonlaunch 1,s :J_,,deo и; 5.,.... $ 1()0 д.. д,, S}p1u9~ •6 .:i• д.:~ Создание пользователя, графический метод 11.3.2. Файлы /etc/passwd и /etc/shadow При добавлении учетной записи происходят следующие действия (вкратце): Добавляется запись в файл • /etc/passwd - это небольшая база данных о пользователях в текстовом формате . Этот файл могут просмотреть все пользователи . Если при создании учетной записи утилита запрашивает пароль, то он • будет внесен в файл /etc/shadow. Пароли в этом файле хранятся в зашиф­ root. Команда p asswd < имя > , из­ пользователя, вносит изменения как раз в этот файл . рованном виде , а доступ имеет только . • меняющая пароль ······-·---··--·----·---·-----·------------·---·----·-------·----·---·---··---·--- -
И , 11т • l .i1111x ....................... t\.1nux Создается домашний каталог /hоmе/<имя>, и в него копируется содержи­ мое каталога /etc/skel. • Создается почтовый ящик пользователя в каталоге • Владельцем каталога /hоmе/<имя> и всех файлов и каталогов в нем /var/spool/mail. назначается создаваемый пользователь . Рассмотрим формат файла /etc/passwd: имя_пользователя:пароль : UID : GID : полное _имя:домашний_каталог:оболочка Вот фрагмент этого файла: evg:x : 1000 : 1000 : evg : /home/evg : /bin/bash mark:x : 1001 : 1001 : : /home/mark : /bin/bash Формат файла /etc/passwd Таблица Формат файла 11.1. Номер поля 1 приведен в таблице 11.1. /etc/passwd Описание Название Имя пользователя Имя , использующееся при входе в систему Поскольку пароль пользователя хра- 2 Пароль нится в файле etc/passwd /etc/shadow, то в файле / вместо пароля просто ука- зывается символ 'х' 3 UID Идентификатор пользователя 4 GID Идентификатор группы пользователя • & 1 - - -----------------·-----------------------·---··-·················-············-··
1JJa вa 11 . n..inux ................. . 1111. 11 . 1111шн·.1111111 р~1111ы Устанавливается администратором и ни на что не влияет. В крупных организациях имя пол ьзователя помогает Полное имя поль- 5 зователя устано вить контакт с пользователем. Это поле может также содержать номер телефона, номер_ комнаты и прочую информацию, которую запрашивает adduser при создании пользо - вател"я 6 Домашний ката- Обычно это /hоше/<имя - пользовате - лог пользователя ля> Программа, которая будет запущена при входе польз9вателя в систему из Оболочка 7 консоли (для графического режима это поле не имеет значения). Список доступных оболочек хранится в файле /etc/shells В файле /etc/shadow passwd, поля полей больше , чем в /etc/passwd. Как и в случае с /etc/ разделяются двоеточиями: 1. Имя пользователя. Совпадает с именем пользователя в файле 2. Зашифрованный пароль. Позже мы поговорим о том, как распознать алго ­ /etc/passwd. ритм шифрования , которым был зашифрован пароль . 3. Количество дней (с l января 1970 года) , когда пароль был сменен в последний раз. 4. Число дней до смены пароля. Если в этом поле О , то пароль может быть сменен в любой момент. 5. Количество дней, после которых пароль должен быть сменен. Обычно здесь з начени е 999999, которое показывает, что пол ьзователь может ни­ когда не менять свой пароль . • ..- ................................................... ·.···· ............. . .. . ..... . - -
Я , 1ро 6. l ,i 1111 х ....................... n.1nux Число дней, в течение которых пользователь получает предупреждение о необходимости изменить пароль. Обычно такие предупреждения пользо­ ватель получает за неделю 7. (7 дней) до часа "Х". Число дней после окончания действия пароля, когда еще пользователь может работать со старым паролем. Если после этого срока пользователь не сменит пароль, учетная запись будет заблокирована. 8. Число дней, начиная с 1 января 1970, после которых пароль будет забло­ кирован . 9. Не используется. Обычно последние три поля не используются. По зашифрованному паролю можно понять, какой алгоритм шифрования использует система. Посмотри­ те на начало зашифрованного пароля: • $1$ - MD5. Ранее часто использовался, сейчас чаще используется SHA512, поскольку в MD5 обнаружились математические уязвимости. • $2$, $2а$ Linux. Blowfish. Чаще используется в FreeBSD/OpenВSD, чем в • $5$ - SHA-256. • $6$ - SHA-512. Используется Форматы файлов в современных дистрибутивах. /etc/passwd и /etc/shadow были приведены "для общего раз­ вития", чтобы вы понимали, что происходит. Модифицировать учетную за­ пись пользователя правильнее с помощью команды редактирования файла /etc/passwd. usermod, а не с помощью Конечно, можно внести небольшие изме­ нения, например, изменить полное имя пользователя. А вот для изменения остальных параметров, например, домашнего каталога, правильнее исполь­ зовать usermod, чтобы потом не делать много ручной работы. 11.3.3. Изменение и удаление учетных записей Как было отмечено, ранее для модификации учетной записи пользователя нужно использовать команду usermod, но прежде поговорим об изменении • ВI- ······································· ···········································
n.iпux _________________ _ l . 1a11a 11 . 1111.11,ншан·. 11111 1 р~11111,1 пароля , так как изменение пароля ~ это тоже, по сути, изменение учетной записи. Для установки и изменения пароля пользователя используется команда passwd: # pass wd <имя> Если пользователь хочет изменить собственный пароль, то указывать имя не нужно: $ passwd А вот теперь можно приступить к рассмотрению команды usermod. Формат вызова этой команды следующий: # usermod [параметры] Параметры команды Таблица 11.2. учетная запись usermod описаны Параметры команды в таблице usermod Параметр -а, -с, -append --comment комментарий 11 .2. Описание Добавляет пользо вателя в дополнител ьную группу. Используется только с параметром Добавляет комментарий для учетной -G записи пользователя Задает новый домашний каталог пользователя . Если указать параметр -т , то текущий до- -d, --home каталог машний каталог пользователя будет перенесен в новый домашний каталог, который будет создан , если не существует ".--- -- ---- -- ------ ---- ---- --- -- -------- ---.---- -- --- ------- -- ---- -.----. ---.-- ----1!11
Я , tро l,inux ....................... n.inux Указывает дату устаревания учетной записи пользователя. По достижении этой даты учет- - е, --expiredate дата ная запись пользователя будет заблокирована. Дата указывается в формате ГГГГ-ММ-ДД. Если дату не указывать, то устаревание учет- ной записи будет отключено После указанного числа дней, которые пройдут после устаревания пароля, учетная запись -f, --inactive дни будет заблокирована. Значение означает, -1 что эта возможность не используется, а О запись будет заблокирована сразу же - после устаревания пароля Указывает имя или пользователя -g, --gid группа первичной группы GID Группа с таким именем/GID должна существовать. Все файлы в домашнем . каталоге пользователя, которые принадлежа- ли бывшей первичной группе, теперь будут принадлежать новой группе Список -G, --groups группа][, группа2, ... , группаN} дополнительных групп, рых находится пользователь. групп осуществляется дополнительных через пробелов. в кота- Перечисление запятую Например , без -G group 1,group2 -!, --login новое_ имя -L, --lock -т, --move-home -о, --non-unique Изменяет имя пользователя на новое Блокирует учетную запись - имя. пользователя. Нельзя использовать этот параметр с -р или -1 Перемещает домашний каталог. Используется вместе с параметром -d При использовании с -и позволяет указать не уникальный ля) UID (идентификатор пользовате- • 111-········································································,··········
lтша n..inux ................. . 11 . r1ш11,юва1сли 111ру1111ы Шифрованное значение пароля, которое возвращает -р, --passwoгd пароль параметр функция не crypt. Использовать рекомендуется , поскольку ЭТОТ дру- гие пользователи увидят незашифрованный пароль в списке процессов Выполняет изменения в каталоге -R, -гооt chгoot chroot и ис- пользует файлы конфигурации из этого каталога Задает оболочку для пользователя. Если обо - -s, --shell оболочка лочка не указана, то будет использована обо лочка по умолчанию -и, --uid UID -И, -Z, --unlock --selinux-useг SEUSER Задает новый UID пользователя, который дол- жен быть уникальным Разблокирует учетную запись пользователя Новый пользователь SELinux для пользова- тельского входа Рассмотрим несколько примеров: # usermod - d /home/new home - m mar k · # usermod - 1 mark # usermod - G admins , sudo mark Первая команда задает новый каталог для пользователя тагk. Теперь он бу­ дет называться /home/new_home. Старые файлы (из каталога /home/ubuntu) будут перемещены в новый домашний каталог. Вторая команда блокирует учетную запись пользователя тагk. Третья ко­ манда вносит пользователя тагk в группы admins Теперь рассмотрим команду useгdel ( см. табл . # userdel • [параметры] и sudo . 11.3): пользователь .. . ... . . . .. .. . . . . . . . . . . .... .. ... . . . . . . . .... .. . ... . .. ... . .. . . . . . . .... ... .. . . . . .. . . . . . .
Я . tро lj1111x Таблица 11.3. ....................... t')_lnux Параметры команды userdel Описание Параметр Удаляет учетную запись, даже если пользователь работает в системе. Также будет удален домашний каталог и почтовый ящик, даже если другой пользаватель использует тот же домашний каталог. Если в -f, --force файле /etc/login.defs параметр USERGROUPS_ENAВ равенуеs, то будет удалена и первичная группа пальзователя, даже если она является первичной и для другого пользователя. Довольно опасный параметр, который может привести систему в нерабочее состояние Удаляет домашний каталог пользователя и почто- -r, --remove вый ящик. Файлы этого пользователя, созданные на других файловых системах, нужно искать и удалять вручную -R, --root chroot Выполняет изменения в каталоге chroot и использует файлы конфигурации из этого каталога Удаляет все пользовательские сопоставления -Z, --selinux-user SELinux для Пример удаления учетной записи учетной записи пользователя ubuntu, домашний каталог и почтовый ящик также будут удалены: # userde l - r ubuntu 11.3.4. .. Группы пользователей Для более простого управления пользователями их можно объединять в группы. Например, можно задать ограничения ресурсов для группы польза• .. .... . . . . . . . . .. . . . . . . . ... ....... ..... . .... .... . ... ......... . .... ........ .... .....
1 1а11а 11 t\.1nux __ . _________ ..... . ll11.11,юв.11t'.lll lt 1р~1111ы вателей. Тогда они будут распространяться на всех пользователей, входящих в группу, и вам не придется их устанавливать для каждого пользователя от­ дельно. Но, прежде чем устанавливать права для группы , нужно эту группу создать . Добавить группу можно командой groupadd, чится, если вы просто отредактируете файл однако ничего плохого не слу­ /etc/group (не groups, а именно group!) и добавите группу вручную. При добавлении группы следите, чтобы ID группы был уникальным. Если же вы не хотите ни за чем следить, тогда просто введите команду groupadd: # groupadd [параметры] С параметрами команды ме - имя группы groupadd можно ознакомиться в справочной систе­ man groupadd. 11.4. Модули РАМ Подключаемые модули аутентификации РАМ (PluggaЫe Modules) тверждения подлинности пользователя. Модули РАМ мире Authentication предоставляют администраторам дополнительные методы под­ Linux. - это не новинка в Они были разработаны очень давно, но до сих пор есть даже в самых современных дистрибутивах Linux, поскольку заменить их, по сути, нечем. Модули РАМ позволяют использовать несколько схем аутентификации. Большинство приложений, которые нуждаются в проверке подлинности пользователя, используют РАМ. Модули РАМ позволяют реализовать аль­ тернативную аутентификацию, например, по отпечаткам пальцев или по сет­ чатке глаз, но для этого необходимо дополнительное оборудование, напри­ мер, сканер отпечатков. В этой книге мы рассмотрим традиционный вариант использования РАМ- когда аутентификация происходит посредством вво­ да пароля с клавиатуры. Основной файл конфигурации называется pam.d/ находится /etc/pam.conf. В каталоге /etc/ конфигурация для разных сервисов , которые поддержива­ ют РАМ, например, в • для /etc/pam.d/sshd находится конфигурация РАМ-модулей SSH, в /etc/pam.d/fly-dm - конфигурация пароля для менеджера дисплея .. ---.. --.. --.. ---.. --------.. ---------... --.--.. --............ -... -............ --tzll •
Ядро Linux ... . .. .. . ... . .... . .. ... t\..inux Fly Display Manager и т.д. В каталоге /etc/security также есть файлы конфигу­ рации, относящиеся к РАМ , например, файл ассеss.соnfуправляет доступом в систему. Безопасность вашей системы зависит от используемых вами модулей. Модули хранятся в каталоге /liЬ/security или /lib64/security (для 64 - битных систем), однако некоторые дистрибутивы не следуют этому стандарту. К примеру, в некоторых системах модули можно найти в каталоге /usr/liЫ security. При желании можно написать и собственные модули, но для начала следует разобраться с уже имеющимися. Ниже приведен список наиболее часто используемь!х модулей. Больше информации по каждому из них мож­ но получить, набрав man модуль, к примеру, тап рат _ywcheck. Обратите внимание , что нет "стандартного списка" модулей . Их состав варьируется от дистрибутива к дистрибутиву. разрешает или запрещает доступ, в зависимости от IР ­ • pam_access - адреса, имени пользователя, имени хоста или доменного имени и т.п. По умолчанию правила доступа определены в файле /etc/secшity/access.conf. Когда пользователь входит, проверяются правила доступа до первого совпадения , и принимается решение , разрешить или запретить д оступ. та·кже смотрите модуль pam_time -там другие ограничения. • pam _ cracklib и pam_pwcheck - предоставляют функции проверки прочности пароля (проверки на легкость угадывания или повторяемость). У пользователя спрашивают пароль , и если он проходит предустановлен­ ные правила и считается прочным , тогда нужно ввести его еще раз дл я проверки правильности ввода. • pam_deny - безусловно зап рещает доступ. Этот модуль можно исполь ­ зовать для блокирования пользователей как политику по умолчанию (см. также pam_permit). • pam_echo - выводит предустановленное текстовое же pam_ inotd. • pam_env - поз воляет присвоение значений переменным окружения. Правила по умолчанию берутся из файла • pam _ ехес • pam_lastlog - сообщение. См. так­ /etc/security/pam_env.conf. вызывает внешнюю программу. выводит дату и время последнего входа в систему. • . ...................................................................................
1 :нана t\.inux ................. . • pam_limits - 11 . lloJ IЫOH.IH'J III II IJ))lllll,I устанавливает ограничения на системные ресурсы, ис­ пользуемые пользователем. Ограничения по умолчанию берутся из фай­ ла /etc/security/limits.conf. • pam_listfile - разрешает или запрещает сервис в зависимости от значе­ ний в файле. К примеру, если вы хотите открыть FТР-доступ лишь для не­ которых пользователей, перечень которых указан в файле /etc/ftpusers_ok, auth required pam_lisifile.so item=user sense=allow file=/etc/ftpusers_ok onerr=fail в файл /etc/pam.d/ftpd (см. также модуль pam_nologin) . нужно добавить строку сообщает пользователю о наличии свежей электронной • pam _ mail почты. • pam_ mkhomedir - создает домашний каталог пользователя, если он не существует на локальной машине. Таким образом, можно использовать централизованную авторизацию (к примеру, в NIS или LDAP) и создавать домашние каталоги лишь при необходимости. выводит "сообщение дня" . См. также модуль • pam_motd • pam_nologin • pam_permit также модуль • pam _ rootok - запрещает доступ, когда существует файл безусловно разрешает доступ - /etc/nologin. • очень небезопасно! (см . pam_deny). разрешает доступ для пользователя ных проверок . Обычно этот модуль используется пользователь pam_echo. root root без дополнитель­ в /etc/pam.d/su, чтобы мог войти под любым другим пользователем даже без ввода пароля . Файл должен содержать следующие строки (обратите вни­ мание на вторущ строку, см . модуль auth auth auth • pam_succeed_if - sufficient required required pam_wheel): pam_rootok . so pam_wheel .s o pam_unix . so проверяет некоторые характеристики учетной записи, к примеру, принадлежность к определенной группе , значение • pam_ time - • и т.п. запрещает доступ к службе в зависимости от дня недели и времени дня. По умолчанию правила берутся из файла conf. UID /etc/security/time. Однако запрет накладывается лишь на момент входа в систему. Спо­ соба принудительно заставить пользователя выйти из системы нет. ................................................................................... .
Янро • [,inux ....................... n.inux раm_umаsk-устанавливает маску создания файлов. или • pam_unix pam_unix2 - классическая аутентификация в /etc/passwd и /etc/shadow (см . также стиле, основана на файлах UNIХ­ модуль pam _ userdb). аутентифицирует пользователя с помощью базы данных • pam_ userdb - (см. также модуль pam_unix). заносит название службы , номер терминала, пользователя • pam_ warn - и друrие данные в системный журнал. Модуль можно использовать везде, он не влияет на процесс аутентификации. • pam_wheel - позволяет rооt-доступ лишь для чл·енов группы Часто этот модуль используется для whee\. su, чтобы лишь избранные пользова­ тели могли пользоваться этой программой. Пример использования можно найти в описании модуля pam_rootok. Если книга не посвящена отдельно РАМ, лучше всего рассматривать РАМ на отдельных примерах . 11.4.1. Файл Ограничиваем доступ к системе по IР-адресу /etc/security/access.conf определить , используется модулем каким пользователям pam_access.so, чтобы позволено входить в систему и с каких IР-адре сов. Если открыть файл access.conf, то в нем будет достаточно много различных примеров, которые хорошо прокомментированы. Если вы знаете английский язык , то не составит особого труда во всем разобраться самостоятельно. Формат этого файла следующий: разрешения пользователи источники Разрешение может начинаться с символа "+" (доступ разрешен) или "-" (доступ запрещен). Если нужно указать несколько пользователей, то их име- • IZII-·················-···--···-·------··------··------- - ·-------·------·---·------·--·
rtiпux _______ ; _. __ .. ___ _ l . 1a11a 11 . Гlо.11,юш11с.111111ру1111ы на разделяют пробелом. Если нужно сделать исключение для некоторых пользователей, то перед их именами указывают служебное слово ЕХСЕРТ. Третье пол1:; может содержать список из одного или более имен консолей (tty) - для несетевого доступа к системе, имен узлов (для сетевого досту­ па), доменных имен (начинаются с".") , IР-адресов узлов , IР-адресов сетей (заканчиваются"."). Также можно указать все источники источников (NONE) или только локальные источники (ALL), ни (LOCAL). один из Теперь несколько примеров: - : ALL Е ХСЕ РТ Первая консоль r oo t:tt y l - это только консоль root. Другим пользователям запреще­ но ее занимать. Мы запрещаем доступ(-) всем пользователям (ЕХСЕРТ) пользователя Следующий пример - root на консоли кроме (ALL) ttyl. разрешение регистрации как root с определ енных IР­ адресов : + + r oot r oot 19 2 . 168 . 1.1 1 92 . 168 . 1.4 192 . 1 68 . 1 . 9 1 2 7 .0 . 0 .1 Если нужно разрешить регистрацию root со всей подсети 192.168.1.0, тогда укажите адрес этой подсети , указав точку вместо О: + r oot 1 92 . 168 .1. Самый жесткий пример r oot - запрещаем root вообще входить в систему: ALL Примечание . Обратите внимание, что комментарии в этом фай­ ле начинаются с #, если вы хотите использовать один из приме­ ров, приведенных в файле, убедитесь, что вы раскомментирова­ ли нужную вам строку. • .. . --.. -. --.. -. -- ... --... -. . .. -... . ........... -... -. ·-. --- .. --.. --...... -. -...• -... -
И 1 1ро l ,inux .......................~ir'i!\.IX Чуть выше мы разрешили вход пользователя root с определенных IР-адресов. К сожалению, одного только редактирования access.conf будет недостаточ­ но . Нужно еще отредактировать соответствующие файлы в /etc/pam.d. Нас интересует регистрация по SSH (telnet уже не используется, поэтому вы бу­ дете регистрироваться по SSH) и обычная регистрация в системе. Поэтому нам нужно отредактировать файлы /etc/pam.d/sshd и /etc/pam.d/system-auth. В этих файлах вам нужно добавить строчку: account requ ired / lib64/security/pam_a cces s. so Если у вас 32-р азрядная система , тогда нужно добавить немного другую строку : account / liЬ/securi t y/pam_ acc e ss . s o requ ired 11.4.2. Ограничиваем время входа в систему Безопасностью системы лучше управлять, когда вы бодрствуете. Поэтому имеет смысл разрешить регистрацию только в это время, например, с 19:00 (вдруг кто-то немного задержится на работе). Откройте файл /etc/security/time.conf и добавьте login ; tty* ! tt yp*; & ! root & admin & ; в него строку: !Al0800 - 1900 Здесь мы разрешаем пользо~ателям регистрироваться только с На пользователей файле 8:00 до time.conf вы root и admin 8:00 по 19:00. это правило не распространяется. Также в найдете еще несколько примеров . Как и в случае с предыдущим файлом , вам нужно изменить файлы pam.d/sshd и /etc/pam.d/system-auth, в account required /etc/ которые нужно добавить строку: /lib64/secu ri ty/pam_time . s o или строку (для 32-разрядной системы): • . . .. . . .. .. . -. -- . -- ......... ---- .............. --- ......... ·- . ·· ·- ... -- ....... -....... ,
n.1пux ................. . re qu ire d acc oun t 11.4.3. lm111a l l . ll11.1 11.ю11:11cJ 111111p~1111ы / liЬ/security / pam_ti m e . so Ограничение системных ресурсов с помощью РАМ С помощью РАМ-модулей можно ограничить системные ресурсы, что по­ лезно для защиты системы от DоS-атаки. Принцип DоS-атаки заключается в том, что злоумышленник узурпирует все ресурсы системы , в результате обычным пользователям ничего не остается . Ограничив системные ресурсы, вы можете смягчить последствия DоS-атаки на ваш сервер. Конечно, полной защиты этот способ не даст, но все равно ваш сервер будет продолжать рабо ­ тать, хоть и медленно. Все же это лучше , чем ничего. Ограничить системные ресурсы можно с помощью /etc/security/limits.conf. Формат записей в этом файле такой: д омен т ип ресурс значение В качестве домена указывается или имя пользователя, или имя группы поль­ зователей ( @имя). Также можно указать звездочку (*), если ограничение должно распространяться на всех пользователей. Ограничения бывают мягкими (soft) и жесткими (hard). Мягкое ограничение можно незначительно превысить , жесткое превысить нельзя . Возможные значения третьего поля задают тип ограничиваемого ресурса и представлены в таблице Таблица 11.4. 11.4. Ресурсы, которые можно ограничить с помощью limits.conf Элемент Описание core Позволяет ограничить размер файла ядра (в килобайтах) cpu Задает максимальное процессорное время (в минутах) data • Определяет максимальный размер сегмента данных (в килобайтах) .. . . -----... --..... ·.. -.... ----. ---. ----. -. ---....... --... -... -.. -. -.. --.. -. . ... -. . -
Ядро Linttx . . . .. . .. . .. ... ... .. . ... r.linux Позволяет указать максимальный размер файла (в килобай- fsize тах) Определяет максимальное количество параллельных регистраций пользователя. По умолчанию пользователю раз- maxlogins решается войти неограниченное количество раз разными способами - по SSH, FTP, • Задает максимальное nofile с разных консолей и т.д. число одновременно открытых файлов Определяет число процессов, которые может запустить nproc пользователь Задает приоритет, с которым будут выполняться процессы priority пользователя или группы Максимальный размер стека (в килобайтах) stack Последнее поле определяет значение лимита. Теперь несколько примеров: * @ssh users @ssh users maxlogins nproc fsize hard hard hard 3 5 24576 В первом случае мы ограничиваем число одновременных регистраций поль­ зователей до 3 (консоль, Xl 1, если есть и но) . Во втором пользователям из группы не более 5 процессов SSH - этого более чем ~sh_ users мы разрешаем достаточ­ запускать одновременно. Также SSН-пользователям не разреша­ ется создавать файлы размером более 24 Мб. Обратите внимание: здесь мы просто задаем лимит на максимальный раз­ мер файла. В принципе, 24 Мб вполне достаточно даже для хранения фото­ графий с зеркальной камеры и больших документов Word, содержащих изо­ бражения и другие объемные объекты. А видео и файлы большего размера пусть пользователи хранят или на своих компьютерах, или входят иным спо­ ... собом, например , по FTP, где можно более качественно ограничить опера­ ции с файлами . ---------·: • --------------------------------- --------------------------- . • --------
n..inux .................. . После редактирования Глава 11. Пользователи II r· руппы /etc/security/limits.conf никакие другие файлы редак­ тировать не нужно. Но описанные вами изменения будут действовать для новых сеансов пользователей, поэтому желательно перезагрузить систему, чтобы изменения действовали сразу для всех пользователей. Если вам нужна дополнительная информация о РАМ, предлагаем ознако­ миться с официальной документацией, доступной по адресу: https://mirrors. edge.kernel. org/puЬ/linuxllibslpam/ • ··································--··············································-
Глава 12. Блочный ввод/вывод
Я ;жро Linux 12.1. ....................... r.linux Блочные устройства Блочные устройства - это физические устройства компьютера, позволя­ ющие выполнять произвольный (а не последовательный) доступ к участкам данных, называемых блоками. Примеры блочных устройств - жесткий диск, DVD-накопитель, флешка. Как правило, блочное устройство содержит файловую систему и прежде, чем получить доступ к данным, нам нужно смонтировать файловую систему. Поэтому можно сказать, что файловая система- это инструмент для "обще­ ния" с блочными устройствами. Кроме блочных устройств в - Linux также есть и символьные устройства это устройства с посимвол ьным вводом-выводом данных. Пример: кла­ виатура, последовательный порт. Получается, что если доступ к данным устройства выполняется в виде потока данных, оно относится к классу сим­ вольных. Вся разница между этими двумя типами устройств в возможности выпол­ - нения произвольного доступа к данным, то есть в возможности устройства выполнить поиск данных, переходя из одной позиции в другую . Взять ту же клавиатуру. Она тоже выдает поток данных. Если вы наберете на клавиату­ ре слово hello, • то драйвер клавиатуры вернет поток из этих пяти символов, • • • . . . . .. .. ................ . .............. . .............................................
l . 1ава 12. rl.inux .............. . r».ю•111ыii 1шо, 1 / иы1ю. 1 расположенных в том порядке , в котором вы их ввели. При этом считывание символов в другом порядке не только невозможно, но и не имеет смысла . Жесткий диск работает совсем иначе. Драйвер жесткого диска может потребовать прочитать содержимое определенного блока, а затем содержи­ мое другого блока, причем эти блоки не обязательно должны следовать друг за другом. Поэтому доступ к данным жесткого диска может выполняться произвольным образом, а не в виде последовательного потока. Таким обра­ зом, жесткий диск относится к блочным устройствам. По сравнению с символьны:м:и устройствами при управлении блочными устройствами в ядре им требуется уделять больше внимания , а также вы­ полнять дополнительную подготовку. Связано это с тем, что символьные устройства имеют всего одну позицию для считывания данных , причем она всегда текущая. В отличие от него блочные устройства могут переме­ щаться в любую позицию на физическом носителе информации . В самом деле , не нужно создавать в ядре целую подсистему для обслуживания сим­ вольных устройств , тогда как для блочных устройств это просто необ­ ходимо . Такая подсистема необходима отчасти из-за сложности блочных устройств . Однако основная причина такой мощной поддержки в ядре со­ стоит в том , что скорость работы блочных устройств напрямую зависит от скорости их обслуживания со стороны процессора. Действительно , выжать максимум производительности из жесткqго диска значительно важнее , чем получить некоторое увеличение скорости при работе с клавиатурой. Более того , как будет показано ниже , сложность блочных устройств обеспечивает большой простор для таких оптимизаций . Далее будет показано , как ядро управляет работой блочных устройств и запросами к этим устройствам . Рассматриваемая часть ядра называется уровн ем бл очного ввода -вывода (Ыосk 12.2. I/0 layer). Структура блочного устройства Наим еньший адресуем ый элеме нт бл очного устройства наз ы ва ет ся сектором. Сектора могут иметь разный размер, который ~ратен размер сектора равен 512 2n, однако чаще всего байтам . Размер сектора определяется физически­ ми параметрами устройства. Сектор является основным элементом любо­ го блочного устройства. Устройства не могут обращаться к блокам данных ,
ЯЩJО l,i11ux ...... ___ . _..... _______ t\.inux размер которых меньше размера сектора , однако большинство блочных устройств при выполнении одной команды позволяет оперировать несколь­ кими секторами сразу. Хотя большинство блочных устройств и имеет раз­ мер сектора, равный 512 байтам, все же существуют и другие стандартные размеры сектора (например , у большинства накопителей на компакт-дисках размер сектора составляет 2 Кбайт) . Примечание. Сектор и блок - физическая единица . Блок логическая. В одном блоке может - это разные вещи. Сектор - это быть несколько секторов. При разработке программного обеспечения преследуются разные цели, ис­ ходя из которых выбирается минимально адресуемая единица данных , кото­ рая называется блоком. Блок - это абстракция файловой системы , т. е . все обращения к файловым системам могут выполняться только с данными, кратными размеру блока. Несмотря на то, что физические устройства сами по себе работают на уровне секторов, ядро выполняет все дисковые операции на уровне блоков. Так как наименьший возможный адресуемый элемент - это сектор, размер блока не может быть меньше размера одного сектора и должен быть кратен размеру сектора. Более того, для ядра (так же как и для "железа" в случае секторов) необходимо, чтобы размер блока был кратен 2". Ядро также требует, чтобы максимальный размер блока не превышал размер страницы памяти . Поэто­ му размер блока равен размеру сектора, умноженному на число, кратное 2", и не может быть больше размера страницы . Чаще всего используются размеры блоков 512 байтов, 1 и 4 Кбайт. 12.3. Буфер ы При сохранении блока в памяти, скажем, посл е выполнения операций чте­ ния или отложенной записи, он записывается в буфер (buffer). В каждый буфер записывается только один блок . По сути, буфер играет роль объекта, представляющего дисковый блок в оперативной памяти . Напомним: блок состоит из одного или нескол ьких секторов и по размеру не может быть больше одной страницы п амяти . a:t ------------------------------------------------------ ------------- ------------_,
1тша 12. n..inux __ ___ ____ __ ____ Блоч11ыii ввод/ выво:1 Поэтому в одной странице памяти может находиться один или несколько блоков. Поскольку для ядра требуется некоторая управляющая информация, связанная с данными (например, какому блочному устройству и какому бло­ ку соответствует буфер), то с каждым буфером связан свой дескриптор. Этот дескриптор называется заголовком буфера (buffer head) и представляется с помощью структуры buffeг_head, которая определена в файле <linux/Ьuffer_ head.h>. В ней содержится вся информация, которая необходима ядру для управления буферами: struct buff~r_head { unsigned long b_state ; struct buffer head *Ь this page ; /* · Флаги состояния буфера*/ /* Сп ис ок буфер о в , находящихся в struct page *b_page ; sector t b_Ыoc k nr ; size_t b_size ; char *b_data ; /* /* /* /* текущей Ссылка странице на Начальный Размер памяти*/ страницу номер памяти* / блока*/ отображе ния* / Ука затель на данные внутри страницы*/ struct Ыосk device *Ь bdev ; /* bh end_io_t *Ь end_io ; /* void *b_private ; /* struct list head Ь assoc_buffers ; /* struct address space *9_assoc_map ; /* Св язанн ое блочное устройство*/ Метод завершения Зарезервировано ввода - вывода*/ для b_end_io */ С писок свя занных отображений список связанных адресных *~ пространств*/ atomic t Ь count ; /* Счетчик использования*/ }; Поле Ь _state хранит состояние буфера, а состояния могут быть следующими : • ВН _ Uptodate - буфер содержит корректные данные. буфер изменен (содержимое буфера новее соответствующих • BH _ Dirty - данных на диске и поэтому буфер ; в конечном счете , должен быть записан на диск). • ВН _ Lock для буфера выполняется операция ввода/вывода с дисково­ - го устройства, поэтому он заблокирован для доступа со стороны других процессов. • BH_Req - буфер включен в запрос на выполнение операции • BH_Mapped - 1/0. буфер содержит корректные данные и отображен на дис­ ковый блок. • • ВН _New - буфер только что отображен с помощью функции get_ Ыо'сk() ·- ·· ·--···· · ·--· ·--- -·--·-·------··· -· ··--··---·--- · · --· ·- -···-----··· · --··---· ··- -
Я , 1р11 l,i1111x • ______ ................. n.1nux ВН _ Async_ Read - для буфера выполняется асинхронная операция чтения с помощью функции • ВН _Async_ Write - end_buffer_ async_read() для буфера выполняется асинхронная операция запи­ си с помощью функции • ВН _Delay - end_buffer_ async_write() с буфером не связан дисковый блок, буфер является последним в последовательности смеж- • BH_Boundary ных блоков. • ВН _Write_EIO при записи буфера произошла ошибка ввода/вывода, • ВН_ Ordered - упорядоченная запись, • ВН _Eopnotsupp - • BH_Unwritten - - операция на заданном буфере не поддерживается , место под данные буфера было выделено на устройстве, но сами данные еще не записаны , • ВН_ Quiet - подавить ошибки при выполнении операций ввода-вывода для этого буфера, В поле b_count хранится счетчик использования буфера, Значение этого поля увеличивается и уменьшается с помощью двух· встраиваемых функций, которые определены в файле <linux/Ьuffer_head.h>, как показано ниже. static inline void get_bh(st ru ct buffer head *bh) ( atomic_inc(&bh->b_count) ; static inline void put_bh(struct buffer head *bh) ( atomic_dec (&bh->b_count); Перед тем как обращаться к полям заголовка буфера, необходимо увели­ чить значение счетчика использования с помощью функции get_bh(). Это гарантирует, что во время работы с буфером он не будет освобожден другим процессом. Когда работа с заголовком буфера будет закончена, необходимо уменьшить значение счетчика ссылок с помощью функции put_bh(). Данному буферу соответствует физический блок с логическим номером b_ Ыocknr, который находится на устройстве b_bdev. lllt···················································· · ,·- ·················-·· ·· ·· '
1 1ава 12. n.inux .... .......... . li. 111•111ыii 1шо. 1 / 11ы110. 1 В поле Ь _yage хранится указатель на физическую страницу памяти, в ко­ торой располагаются данные буфера. В поле Ь _data хранится указатель на данные блока, расположенные на странице памяти Ь _yage, размер блока хранится в поле Ь_size. Следовательно, блок хранится в памяти , начиная с адреса b_data и заканчивая адресом (b_data + b_size). Заголовок буфера предназначен для описания соответствия между дисковым блоком и буфером, находящимся в оперативной памяти компьютера и пред­ ставляющим собой последовательность байтов, которые расположены в ука­ занной странице памяти. Единственное назначение этой структуры данных ядра вып9лнение роли дескриптора отображения "буфер-блок". - 12.4. Планировщики ввода/вывода Ожидающие события ввода-вывода планируются или сортируются с помо­ щью ал.горитма постановки в очередь, также называемого лифтом tor), (eleva- поскольку аналогичные алгоритмы можно использовать для наиболее эффективного планирования лифтов. Не существует единого лучшего алго­ ритма, выбор зависит от вашего оборудования и от рабочей нагрузки. Настройка выполняется по диску, а не по разделу, поэтому, если на первом диске есть разделы, содержащие /, /Ьооt и /Ьoot/efi, все три файловые систе­ мы должны обрабатываться одинаково. Поскольку вещи в /Ьооt нужны лишь изредка после загрузки, если вообще когда-либо, то рассмотрите возмож­ ность использования вашего корневого раздела для выбора алгоритма для всего /dev/sda. Настройка выполняется с помощью объекта ядра /sys/Ьlock/sd*/queue/sched­ uler. Вы можете прочитать его текущее содержимое с помощью команды cat. В выходных данных перечислены все алгоритмы организации очередей, поддерживаемые ядром. Используемый в настоящее время, заключен в квадратные скобки: # grep . /s ys / Ыock / sd* / queue / scheduler /sys/ Ьlo ck/sda/queu e / scheduler:noop / sys/Ьlock/sdЬ/q ueue /sc heduler:noop / sys/Ыock/sdc/queue/scheduler :n oop / sys / Ьlock / sdd/queue /sc heduler:no o p • deadline deadline deadline deadline [cfq] [cfq] [cfq] [cfq] ·--------------- ------ ------ ---- -------------------------------------------------- \
Ядро ..... ________ ......... . t\.iпux [,inux Вы можете изменить содержимое объекта ядра и выбрать другой алгоритм с помощью echo: # cat /sys/Ьlock/sdd/queue/scheduler noop deadline [cfq] # echo deadline > /sys/Ьlock/sdd/queue/scheduler # cat /sys/Ыock/sdd/queue/scheduler noGp [deadline] cfq Если вам лень :1итать дальше, то можем вкратце сказать следующее: исполь­ зуйте deadline для интерактивных систем (рабочие станции, персональные компьютеры) и поор для автоматических вычислений . Далее мы разберемся с планировщиками ввода/вывода более подробно . 12.4.1. Алгоритм deadline Алгоритм крайнего срока (deadline) пытается ограничить максимальную задержку и сделать людей счастл ивыми . Каждому запросу ввода-вывода назначается свой крайний срок, и он должен быть выполнен до истечения этого таймера. Для каждого устройства поддерживаются две очереди , одна сортируется по секторам , а другая по крайнему сроку. Пока сроки не истекли, запросы вво­ да-вывода выполняются в порядке секторов , чтобы свести к минимуму дви­ жение головки и обеспечить наилучшую пропускную способность. Данный алгоритм подойдет в следующих случаях : 1. Ваша система используется интерактивно. В вашей рабочей нагрузке преобладают интерактивные приложения или пользователи жалуются на низкую производительность работы диска . 2. У вас есть база данных с большим количеством операций ввода/вывода. 3. Операции чтения выполняются значительно чаще , чем операции запи­ си , поскольку приложения чаще блокируются в ожидании именно чтения данных ... . . -. .. -... --. . . -.... -.... . .. : ............... -....................... -............. .
n..iпux .............. . 1J 1ава 12. БJJОЧIIЫЙ BBOJ t/Bl,ШOJ t 4. Ваше оборудование для хранения данных представляет собой массив сеть хранения данных) или массив SAN (Storage Area Network, RAID с большими буферами ввода/вывода. 12.4.2. Алrоритм CFQ Алгоритм CFQ (Completely Fair Queuing) или полностью справедливой организации очередей сначала делит процессы на три класса: в режиме реального (Jремени, с максимальной эффективностью ствия (Idle). (Best Effort) и бездей­ Процессы реального времени обслуживаются раньше процес­ сов максимальной эффективности, которые, в свою очередь, обслуживаются раньше процессов бездействия. • Внутри каждого класса ядро пытается предоставить каждому потоку одина­ ковое количество временных интервалов. Процессы по умолчанию относят­ ся к классу Best Effort, и вы можете изменить приоритет ввода-вывода для процесса с помощью команды ionice. Ядро использует последние шаблоны ввода-вывода, чтобы предвидеть, будет ли приложение выдавать больше за­ просов в ближайшем будущем, и если ожидается больше ввода-вывода, ядро будет ждать, даже если другие процессы имеют ожидающие ввода-вывода. Алгоритм CFQ может улучшить пропускную способность за счет уменьше­ ния задержки . Пользователи чувствительны к задержке, и им не понравится результат, когда их приложения связаны CFQ. Кому подойдет данный алгоритм: • Пользователи не используют систему в интерактивном режиме, во всяком случае регулярно. • Вы не используете файловую систему большую часть параллелизма в 12.4.3. Планировщик NOOP XFS, поскольку CFQ подавляет XFS. Алгоритм NOOP ничего не делает для изменения порядка или приори­ - тета, он просто обрабатывает запросы в том порядке, в котором они были отправлены • . .. . . . . . . . . . . . . . . . . . . . . . . . --------------------. --. --------------. -.• --------. ------.
И , 1ро J,iпux _______________________ n..inux Это может обеспечить наилучшую пропускную способность, особенно в подсистемах хранения, которые обеспечивают собственную организацию очередей, таких как твердотельные накопители, интеллектуальные контрол­ леры RAID с собственным буфером и кэшем , а также в сетях хранения дан­ ных. Обычно это приводит к наибольшей задержке, поэтому это плохой выбор для интерактивного использования. Причины использования планировщика поор : • Ваша главная забота - пропускная способность, задержка вас не волну­ ет. Пользователи не используют систему интерактивно. • Ваша рабочая нагрузка связана с процессором: большую часть времени мы ждем, пока процессор что-то завершит, события ввода-вывода отно­ сительно малы и широко разнесены. Оба они предполагают, что вы выполняете высокопроизводительные авто­ матические задания, такие как интеллектуальный анализ данных, научные высокопроизводительные вычисления или рендеринг. 12.4.4. Настройка планировщиков Настройка планировщиков ввода:вывода заключается не только в выборе нужного планировщика. У каждого планировщика есть свои параметры, ко­ торые можно изменить с помощью файловой системы sysfs. Различные файлы (атрибуты) появляются в подкаталоге (объекте) queue/ queue/ iosched при изменении содержимого (настройки) файла (атрибута) scheduler. Проще увидеть, чем объяснить. Сами каталоги дисков содержат одинаковые файлы и подкаталоги, включая файл queue/scheduler и подката­ лог queue/iosched/: # 1s - F /sys/Ыock/sdЬ/ alignment_offset discard alignment holders/ bdi@ events inflight capability events_async power/ dev events_poll_msecs queue/ device@ ext range range В!I removaЬle ro sdЬl/ size slaves/ stat subsystem@ trace/ uevent . ·-.-.-.·----.. ----........... -... -... ---... -........ -... -... --............ -... ---.
1: 1ана 12 . r.tinux ______________ _ # ls - F /sys/Ьlock/sdЬ/queue add random max hw sectors kb discard_granularity max_ integrity_segments discard_max_bytes max sectors kb discard zeroes data max segment size hw sector size max_segments iosched / min i mum io size iostats nomerges logical Ыосk size nr_request Б.юч11ыii вво, 1 / выво. 1 optimal_i o_size physical_Ыock_size read ahead kb rotational rq_affinity scheduler write same_ max_bytes Давайте назна~им три разных планировщика и посмотрим , какие настраива­ емые параметры появляются в их подкаталогах queue/iosched: # echo cfq > /sys/Ьlock/sdЬ/queue/scheduler # echo deadline > /sys/Ыock/sdc/queue / scheduler # echo noop > /sys/Ьlock/sdd/queue/scheduler # ls - F /sys/Ьlock/sd[bcd]/queue/iosched / /sys/Ьlock/sdЬ/queue/iosched/: back seek max fifo_expire sync back_seek_penalty group_idle fifo_expire_async low_latency quantum slice_async slice_async_rq slice idle slice_sync target latency write_ expire writes starved /sys/Ыock/sdc/queue/iosched/: fifo batch front_merges read_expire /sys/Ыock/sdd/queue/iosched/ : Планировщик cfq имеет двенадцать читаемых и настраиваемых параметров, планировщик крайнего срока - пять , а планировщик noop - ни одного (что логично, поскольку это не планировщик вообще) . Настройка планировщика В таблице щика CFQ. 12.1 приводится CFQ описание настраиваемых параметров планиров­ Не все параметры полезны, поэтому в таблице только те, которые вам , может быть, придется изменить на • 12.1 приводятся практике . .. . . . . . . . . . . . . . . . . -... -........ - ....... -... -............... -...................... -
Ящ>о l , iщ1x Табл ица . .. . . . .... .. ..... . . .... 12.1. Параметры план ировщика n.iпux CFQ О писание Атрибут Количество миллисекунд, в течение которого асин- хронный запрос (буферизованная запись) может оставаться необслуженным . fifo - expire- async Если требуется более низкая задержка буферизо в анной записи, уменьшите значение по умолчанию до 250 мс или рассмотрите возможность переключения на планировщик deadline Количество миллисекунд, в течение которых син- хронный запрос (чтение или 1-iебуферизованная за- пись O_DIRECT) может оставаться необслуживае- .fifo_ expire_sync мым. Если требуется более низкая задержка чтения, уменьшите ее со 125 мс по умолчанию или рассмотрите возможность перехода на планировщик О = deadline отключено: задержка игнорируется , каждому процессу предоставляется полный квант времени. 1=включено: low_latency справедливость пропускной способ- ности, установите максимальное время ожидания 300 миллисекунд для кю~дого процесса, выдающего запросы ввода-вывода для устройства. Подойдет для потоковой передачи мультимедиа-данных в реальном времени Количество запросов ввода-вывода, отправляемых на устройство одновременно, что ограничивает глубину очереди. Увеличьте это значение, чтобы повысить quantum пропускную способность оборудования для хранения данных с собственным глубоким буфером ввода1 вывода, такого как SAN и RAID за счет увеличения задержки j • ID--.. ··-· --............ -.. ··-... -... ---··· --·--....... --....... -.... -.. ·-.......... j
1J1a11a 12 . rt..inux .............. . J;J ю•1111,1ii 1ш0J t/н1.11ю1 1 Время в миллисекундах, в течение которого cfq будет простаивать в ожидании дальнейших запросов. Установите О для твердотельных накопителей или для внешнего slice idle RAID с собственным кэшем. Оставьте значение по умолчанию него хранилища без 8 миллисекунд для внутрен­ RAID, чтобы уменьшить количе- ство операций поиска Настройка планировщика Таблица 12.2 deadline содержит параметры планировщика dead/ine, мы сейчас их и рассмотрим. Таблица 12.2. Параметры плаtlировщика Атрибут deadline Описание Количество операций чтения или записи, выполняемых в одном пакете. Более низкие значения могут дополнительно умень- . fifo _ batch . шить задержку Более высокие значения могут увеличить пропускную способность на вращающихся механических дисках (HDD), но за счет меньшей задержки. Вы выбрали планировщик deadline чтобы ограничить задержку, поэтому, вероятно, не хотите ее увеличивать Количество миллисекунд, в течение которых должен быть обслужен запрос на чтение. Уменьшите это read_expire значение с 500 по умолчанию до 100 в системе с инте- рактивными пользователями. Помните, что задержка выше • ..... ... . - 100 мс будет раздражать пользователей ·: ·· ........... -- .... -....... -.... -............. ···- --.......... --...... -
Я . tро [,inux _______________________ n.inux Количество миллисекунд , в течение которых должен быть обслужен запрос на запись. Оставьте значение по write_ expire умолчанию 5000, пусть операции записи выполняются асинхронно в фоновом режиме, если ваше приложение не использует много синхронных операций записи Число пакетов чтения, которые могут быть обработаны writes- starved перед обработкой пакета записи. Увеличьте это значение по умолчанию, равное 2 , чтобы дать более высокий приоритет операциям чтения 12.5. Настройка общих параметров блочного ввода/вывода В /sys/Ьlock/sd*/queue вы можете настроить параметры, представленные в таблице Таблица 12.3. 12.3. Общие параметры блочного Атрибут 1/0 Описание . . Максимально допустимый размер запроса ввода/вывода в килобайтах, который должен находиться в еле- тах - sectors- kb дующих пределах: = max(l, logical_Ыосk_ size/ 1024) Максимальное значение = max- hw sectors- kb - Минимальное значение & 1 - -------------------------------------------------------------------------------- - ·
t'l.iпux I ~ 1ава ______________ _ 12. Б. 10•111ыii вио. 1/ выво, 1 Максимальное количество запросов на чтение и за- пись, которые могут быть поставлены в очередь одновременно, прежде чем следующий процесс, запрашивающий чтение или запись, будет переведен в спящий режим. Значение по умолчанию запросов на чтение и nr_requests 128 128 означает, что 128 запросов на запись могут быть поставлены в очередь одновременно. Большие значения могут увеличить пропускную способность для рабочих нагрузок, записывающих множество небольших файлов, меньшие значения · увеличивают пропускную способность при больших операциях ввода-вывода. Вы можете уменьшить это значение, если используете приложения, чувствительные к задержке Если он не равен нулю, устройство хранения само сообщило о своем собственном оптимальном размере optimal_io_size ввода-вывода. Если вы разрабатываете свои собственные приложе- ния, делайте его запросы ввода-вывода кратными этому размеру, если это возможно Количество килобайт, которое ядро будет читать вперед во время операции последователыюго чтения . кбайт по умолчанию, если диск используется с read- ahead- kb 128 LVM, сопоставитель устройств может использовать более высокое значение. Если ваша рабочая нагрузка выполняет много больших потоковых операций чтения, большие значения могут повысить производительность Должно быть О для твердотельных дисков, но некоторые из них неправильно сообщают о своем состоянии ядру. rotational Если неправильно установлено значение 1 для SSD, установите его на О , чтобы отключить ненужную логику планировщика, предназначенную для уменьше- ния количества операций поиска " ·--------------------------------------------------------------------------------- -
Глава 13. Механизмы кэширования чтения и записи ядра Linux
____________________ . _. n.iпux Я , tро l,i1111x 13.1. Дисковый кэш и отложенная запись Когда заканчивается физическая оперативная память, неиспользуемые в текущий момент данные могут быть перемещены на диск в область подкачки (об этом мы поговорим отдельно). Освобожденная область памя­ ти будет использоваться для хранения данных и кода, необходимый систе­ ме в данный момент времени. Когда данные, сброшенные в область под­ качки (swap, своп), снова понадобятся системе, в своп будут выгружены другие ненужные прямо сейчас системе данные, а эти будут загружены во вновь освободившееся пространство. Понятно, что такой механизм су­ щественно замедляет обработку данных, но зато позволяет обрабатывать больше данных, чем может поместиться в физической памяти . Исходя из этого, самый простой способ увеличить производительность компьютера - добавить оперативной памяти. Тогда меньше данных будет сбрасываться на диск и повысится скорость их обработки. Следующий недорогой способ модернизации - переход на SSD-накопители, скорость работы которых в несколько раз превышает скорость работы с обычными жесткими дисками, поэтому операции с областью подкачки будут осуществляться в несколько раз быстрее. Получается , что, используя механизм подкачки, мы теряем в производитель­ ности . Нужно чем-то данные потери компенсировать . Как раз на этот случай . . . . ------------ ------------------------------- ------ --- ---------- --- ------------- _,
n..inux ........... . в ядре Linux 1, lalШ 1.1 . \\!':\,IIIIIHll,I l,llllll(JIШ,1111111 '111'11111111 1.1111\CII 11. 1();\ \ , il\\l\ реализована дисковая кэш-память, которая называется стра­ ничным кэшем, (page cache). Процесс, благодаря которому изменения, внесенные в станичный кэш, сохраняются на диске, называется отложенной записью страниц (page writeback). Говоря простыми словами, данный механизм позволяет повысить произво­ дительность дисковых операций . Дисковый кэш является о:ень важным компонентом системы по следующим причинам: • Доступ к данным, хранящимся на диске, осуществляется на несколько порядков медленнее, чем доступ к оперативной памяти (миллисекунды против наносекунд). С точки зрения CPU доступ к данным, расположен­ ным в оперативной памяти компьютера, выполняется намного быстрее, чем на диске, а выборка данных из кэш ей первого и второго уровня L2) • (L 1 и процессора выполняется еще быстрее. Если к некоторым данным осуществлялся доступ, то с достаточно боль­ шой степенью вероятности к этим же данным в ближайшем будущем потребуется обратиться снова . Принцип, согласно которому операции обращения к некоторым дан~ым имеют тенденцию группироваться друг с другом во времени, назьiвается временной локализацией • (temporal locality). Он гарантирует, что если данные кэшируются при первом доступе к ним, то существует большая вероятность того, что при следующем обращении к ним в ближайшем будущем они будут находиться в кэш-памяти. Тот факт, что доступ к памяти выполняется намного быстрее, чем к диску, а также высокая вероятность повторного использования данных, находЯ­ щихся в кэше, позволяют добиться существенного увеличения произво­ дительности системы в целом 13.2. Методы кэширования Страничный кэш состоит из страниц физической памяти. Содержимое этих - страниц соответствует физическим блокам на диске . Размер кэша может • .. . --. -----.......... -............ -.......................... -........ -....... . ...
Ядро [,inux ....................... n..inux динамически изменяться - это вполне естественно. Когда есть свободная па­ мять, он увеличивается, когда памяти не хватает - он уменьшается. Устрой­ ство хранения данных, которое кэшируется, называется внешней памятью, поскольку в этом случае диск как бы расположен за пределами кэша и ис­ пользуется в качестве первоисточника данных, которые в нем хранятся. Прежде чем начать операцию чтения, например, если из приложения вызы­ вается функция read(), ядро сначала проверяет, находятся ли нужные данные в страничном кэше. Если они там есть, то дисковая операция не выполняется, а данные копируются прямо из памяти. Если данные были найдены в кэше, тогда это считается удачной попыткой (cache hit), а вот если данных там (cache miss). После неудачной блочных операций I/O, чтобы считать не было, тогда поп'ытка считается неудачной попытки ядру нужщ) выполнить ряд данные с диска. Как только эти операции будут выполнены, ядро помещает считанные с диска данные в страничный кэш. Все последующие обращения к этим данным будут выполнены из кэша, обращений к диску не будет. Нуж­ но отметить , что кэшируются только те данные, к которым осуществляется доступ. Если программа, например, прочитала только часть файла, то только эта часть будет помещена в кэш, а не весь файл. С кэшированием чтения все понятно. А что насчет кэширования записи? Представим, что некоторое приложение выполняет системный вызов write(). Далее может использоваться одна из трех стратегий: 1. Без кэширования (nowrite) - записываемые данные кэшироваться не будут. Если в кэше находится фрагмент данных, соответствующий тому, который в настоящий момент выводится процессором на диск, то этот фрагмент в кэше будет аннулирован. В результате при следующей опе­ рации считывания этого фрагмента с диска он будет снова загружен в кэш. В результате при следующей операции считывания этого фрагмента с диска он будет снова загружен в кэш-память. Такая стратегия очень ред­ ко используется при реализации кэш-памяти, так как при этом не только не кэшируются записываемые на диск данные, но еще и аннулируется содержимое кэша. В результате снижается производительность дисковой подсистемы и увеличиваются накладные расходы. 2. Кэш со сквозной записью (write-through cache)- данные, записываемые на диск, одновременно обновляются как в дисковом файле, так и в па­ мяти . Данные после обновления кэша незамедлительно сбрасываются на диск. В этой стратегии данные в кэше и во внешней памяти находятся • 11!1 ·.. --.. --... -... --... -"". -.".... -.-.... ".. "" ... -".. "-.. --... --... --".. -."-... ---..
n..iпux ........... . 1 ·лава 13 . Мсхашвмы к111111р1ша111111 •11с111111111а1111с1111 1 1pa l.i1шx в согласованном состоянии. Не нужно аннулировать содержимое кэша. Также нужно отметить простоту этой стратегии. 3. Отложенная запись (write-back) - данные при записи помещаются непо­ средственно в страничный кэш. Незамедлительное или непосредствен­ ное обновление внешней памяти не выполняется. Вместо этого страницы с обновленными данными в кэше помечаются как несохраненные (dirty) и помещаются в список несохраненных страниц ществует специальный процесс, называемый (dirty list). В системе су­ writeback, который перио­ дически сохраняет страницы, находящиеся в этом списке, на диск. В ре­ зультате _происходит синхронизация данных, находящихся в памяти и на диске. После этого признак не сохранения страниц сбрасывается. Страте­ гия с отложенной записью считается более прогрессивной по сравнению со стратегией со сквозной записью. Из-за переноса операции сохранения на более поздний срок система может собрать все измененные до этого момента данные и записать их на диск за один раз. Производительность дисковой системы существенно повышается, как и сложность реализа­ ции стратегии кэширования. А что насчет удаления данных из кэша? Ведь его объем не безграничный и мы. не можем прокэшировать все на свете, поэтому нужно проду­ мать алгоритм удаления данных из него. В алгоритм вытеснения данных из кэша в Linux Linux для этого используется (cache eviction). Вытеснение данных выполняется путем простой выборки синхронизированных (т.е. тех, что уже сохранены на диске) страниц памяти и замещения их содер­ жимого чем-нибудь другим. Если таких страниц недостаточно в кэше, ядро запускает процесс отложенной запис и , чтобы можно было освободить до­ полнительные страницы. Самое сложное здесь решить, что именно нужно вытеснять. Нужно избавляться от тех страниц памяти, к данным которых не будут обращаться в ближайшем будущем. Понятно, что чтобы знать какие именно страницы нам 1:1е понадобятся в будущем, нужно как-то заглянуть в это будущее. По этой причине такую стратегию ч.асто называют алгоритмом предсказа ния. Очевидно , что данная стратегия просп~ идеальна, но ее невоз -. можно реализовать. Поэтому вместо стратегии предсказания используется либо стратегия ми­ н.~ин ал ьного использования (в различных ОС) либо стратегия с двумя списками (в • . Linux). Начнем со стратегии минимального использования . " " " " " . " " " " " " . " " " " " " . " """" " .. " "" ... .. "" "" ". """ .. """. """ .. ".".". ". " .. " "" .. " "". """" ...
И , 1ро [,i1шх ________ . ___ .. __ . ______ t't.inux Одним из самых удачных алгоритмов аппроксимации, особенно для кэш­ памяти общего назначения, считается алгоритм замещения элемента с са­ мым старым временем последнего обращения (least recently used, LRU). Для LRU требуется, чтобы с реализации стратегии вытеснения по алгоритму каждой страницей кэш-памяти бьmа связана временная метка, фиксирующая время последнего обращения к ней, либо чтобы список всех страниц кэш­ памяти был упорядочен по времени последнего обращения. Тогда можно легко удалить страницы с самым старым временем последнего обращения или удалить страницы, находящиеся в начале списка (при условии, что стра­ ницы с недавним временем обращения находятся в его конце). Чем дольше к фрагменту данных, находящихся в кэш-памяти, никто не обращается, тем меньше шансов на то, что к нему кто-то обратится в ближайшем будущем. Все довольно просто , Однако есть и недостаток, который проявляется при однократном доступе к множеству файлов на диске. В таком случае помеще­ ние всех страниц с самым старым временем последнего обращения в начало списка не является оптимальным. Как и прежде, ядро не может знать за­ ранее, сколько раз будут обращаться к каждому конкретному файлу. Однако ядру известно, сколько было обращений к файлу за прошедший интервал времени. Теперь перейдем к стратегии с двумя списками (two-list strategy). Вместо поддержки одного списка элементов, упорядоченных по времени последне­ го обращения (так называемый список LRU), в Linux используются два списка: активный и пассивный. Страницы, находящиеся в активном списке, рассматриваются как "необходимые", и по этой причине их нельзя вытеснять. Страницы из пассивного списка могут быть вытеснены из кэша. Страницы помещаются в акт!iвный список, только если при обращении к ним они на­ ходятся в пассивном списке. При обслуживании обоих списков используется псевдо-LRU подход: элементы добавляются в конец списка и удаляются из его начала так же , как и в очередях. Размеры этих списков поддерживаются примерно одинаковыми. Если активный список становится слишком длин­ ным по сравнению с неактивным списком, часть его элементов переносится в неактивный список и становится доступной для вытеснения. Стратегия с использованием двух списков позволяет избавиться от недостатка класси­ ческого алгоритма LRU, связанного с однократным доступом к большому числу элементов. Она позволяет применить простой псевдо-LRU подход для управления элементами списков. Описанный выше подход с двумя списка­ ми часто называют LRU/2. Его можно LRU/n. обобщить для случая с n-списками, и тогда он будет называться • . . . --.................... . .................. -· ............. -.... -............ -..... .
1 1,11\,1 1\ rl.tnux .. ......... . 13.3. \Jex:11111 l\11,1 1, )11111/)0IHIIIIOI '111.'111111 11 lШIIICJI 11,1р:1 (jщ1х Кэширование н а практике Как уже отмечалось, ядро раций чтения и записи Linux для повышения производительности опе­ использует собственный механизм кэширования , называемый кэшем страниц или дисковым кэшем. Основная цель данного механизма - копировать данные и двоичные файлы из хранил ища в память , тем самым сокращая дисковые операции ввода-вывода и повышая общую производительность. По умолч~нию вся свободная физическая память используется операцион­ ной системой для целей кэширования страниц , и в зависимости от рабочих нагрузок операционная система управляет своим состоянием, к э шируя , повторно используя и удаляя файлы по мере необходимости . Даже при текущей более высокой пропускной способности SSD-накопител ей кэширование файлов в памяти приводит к повышению производительности системы . Также довольно распространено заблуждение, что операционная система Linux использует слишком много памяти для кэша и это может отрицатель­ но сказаться на пользователях систем с небольшим объемом ОЗУ, пользова­ телей ноутбуков и мини-систем. На самом деле это хорошо. Использование большого объема памяти под кэш означает, что многие вещи уже кэширова­ ны и многие из наших приложений будут работать быстрее из памяти. Важно всегда помнить, что кэшированная память всегда является свободной доступной памятью, которая будет освобождаться по мере необходимости. Если процессу нужно будет больше памяти, то она будет получена за счет кэша . Давайте посмотрим, как работает кэш на практике на примере использова­ ния файла размером 2 Гб. На момент проведения следующего эксперимента (если вы хотите повторить за нами) убедитесь (команда/rее - h), что у вас больше свободной памяти, чем размер файла, который вы будете читать. В нашем случае свободной памяти должно быть больше чем 2 Гб . Посмотрим, что у нас с памятью до начала эксперимента : # free - wh Me m: Swap : • to tal 5 . 8G u sed 9 4М fre e 5 . 7G ов ов ов s hared 608 К b uffe r s c ache 2 . lM 49М availaЫe 5 . бG .. -------- --. ---. ----. ---. ---. ----. ---. ---.. ---- ---.. ---. ---.. -------------------. . .
Ящ)() l.i11Ux _______________________ n.inux Далее мы сгенерируем файл размером 2 Гб и сбросим все кэши: # head - с 2G </dev/urandom > dummy . file # echo 3 > /proc/sys/vm/drop caches Затем мы подсчитаем количество строк в файле и вычислим продолжитель­ ность выполнения этой операции: # time wc - 1 dщnmy.file 8387042 dummy . file real 0m3.731s user 0m0.278s sys 0ml . 223s Выполним ту же команду снова : # time wc - 1 dummy . file 8387042 dummy . file real 0ml . 045s user 0m0 . 575s sys 0m0 . 471s Второе выполнение заняло гораздо меньше времени, потому что файл был закэширован в страничном кэше, и это само по себе улучшило операцию чтения. Давайте еще раз посмотрим, что у нас с памятью: _# free - wh total Mem : 5.8G Swap : ов used 94М free 3 . 7G ов ов Свободной памяти стало на shared 608К 2 buffers 2.lM cache • availaЫe 2 . lG 5 . SG ГБ меньше, а использование буферов и кэша значительно увеличил ось. Кэш - это часть памяти, в которой хранятся файлы и двоичные файлы, таки е как общие библиотеки, данны е, чтобы будущие запросы на эти дан­ ны е м огл и обрабатываться быстрее. Буферы - это метаданные, относящиеся к кэ шу. a t --------------------------------------------------------------------------------'
n..inux ........... . 1. 1а11а 13 Mt·x:11111 !\JЫ 1.: 111111р1111:1111111 •1 н· 111111 11 1a1111t·11 11 111а l .i1111, Снова сбросим кэши: # sysctl - w vm . drop caches=З Далее мы будем использовать команду vmtouch, с помощью которой можно увидеть, прокэширован файл (или его части) или нет. # vmtouch - v dummy . file dummy . file [ ]0/52 428 8 Files: 1 Directories : О Resident Pages : 0/524288 0/2G 0 % Elapsed: 0 . 013999 seconds Затем опять прочитаем наш файл: # time wc -1 dummy . file 8387042 dummy .file real OmЗ . 732s user Om0 . 284s sys Oml . 539s Посмотрим, что скажет vmtouch: # vmtouch - v dummy . file . file [OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOJ524288/52 4288Files : 1 Directories : О Resident Pages : 524288/524288 2G/2G 100% Elapsed : 0 . 024309 seconds dщmny Как видим, наш файл прокэширован полностью. Все это хорошо и понятно, когда размер доступной оперативной памяти пре­ вышает размер файла, который мы пытаемся прочитать. Но не всегда это так. Что будет с кэшем, если мы попытаемся прочитать файл, размер которо­ го больше, чем объем доступной памяти? • .... ------ ------- ------.---... ---.. --- ------- --------- --.. ---- -- ------. ----- -----·ID
Я . tро l,inux _______________________ t'l.1nux Закэшируем большой файл: # time wc - 1 big . file 33544011 big . file real Om14 .4-26s user Oml . 202s sys Omб . 737s # vmtouch - v Ыg Ыg . file .file [ 00000000000000000000000000000000000000000) 1621005/2097152 Files : 1 Directories : О Resident Pages: 1621005/2097152 6G/8G 77.3 % Elapsed : 0.077948 seconds Размер файла только 6 Гб. 8 Гб, но как мы видим из вывода vmtouch, закэшировано было Что с производительностью? Давайте прочитаем файл еще раз: # time wc - 1 big . file 33544011 big . file real Oml4 . 260s user Oml.959s sys Om4.741s При повторном чтении производительность не увеличилась. Почему? Как видно из вывода vmtouch, "голова", то есть начало файла в кэш не попала. Хорошо , а что произойдет, если мы попытаемся прочитать хвост файла? Да­ вайте попробуем: # time tail - 5000000 big . file >/dev/null real Om4 . 696s user Om2 . 687s sys Om2 . 001s Как видите, при чтении файла с конца, мы получили прирост в производи­ тельности . Получилось как бы скользящее · окно (рис. 13 .1) и голова файла не попала в кэш. • 1111-··· ···-···-.. ·-·· -..... -·-· -.... ·--... -···-· ..... ···-· ---· ···-· ... ···-.......... .
t'l.iпux ........... . ' l . 1ава IJ . i\lсха11111мы 1,;ш111рона111111 ч1с1111я 11 3ап11с11 sцра J,in11x tail head ...... - " tail - ------------- --head Рис. 13.1. " Начш~о файла не прокэшировано Кэш страниц прост, встроен в ОС и обеспечивает явные улучшения произво­ дительности при чтении и записи данных. Играет важную роль в собствен­ ных процессах Linux и совместном использовании данных, оптимизируя вы­ полнение ядра и пользовательского пространства. • ........................................ .............. .......... .................... •
Глава 14. Устройства и модули
Я!lрО [,inux 14.1. _______________________ n.iпux Типы устройств Как ранее было упомянуто, в Linux существует три типа устройств: блочные, • символьные и сетевые. • Блочные устройства (Ыkdevs) позволяют адресовать фрагменты дан­ ных, находящиеся на устройстве и называемые блоками. Обычно такие устройства поддерживают операцию позиционирования, бла­ годаря которой возможен произвольный доступ к данным . Примеры блочных устройств: жесткие диски, DVD-накопители , флешки. Для доступа к блоч­ ным устройствам используется специальный файл, называемый узлом блоч­ ного устройства (Ыосk device node ), который, как правило, смонтирован в виде отдельной файловой системы. • Символьные устройства (cdevs) не позволяют адресовать отдельные блоки данных, они предоставляют доступ к данным только в виде непре­ рывного потока символов (байтов). Примеры: клавиатура, мышь, прин­ теры, а также практически все псевдоустройства. Для доступа к символь­ ным устройствам используется специальный файл, называемый узлом символыюго устройства (character device node). В отличие от блочного устройства приложение взаимодействует с символьным устройством на­ прямую через узел этого устройства. • .... ------- ------ ----- -------------------------- ------------------ --------- ---------. •
l ~ ia вa n.inux .............. ... . • Сетевые устройства (netdevs) 14. Ус·, ройства и моду: 111 предоставляют доступ к сети, напри­ мер, к Интернету, с помощью физического адаптера (например, сетевой адаптер Ethernet или беспроводной адаптер 802.11 (Wi-Fi)). В отличие от других типов устройств, обращение к этим устройствам выполняется че­ рез специальный интерфейс, называемый АРl-сокетом (socket API). Чтобы система могла работать с устройством, ей необходим драйвер этого устройства. Именно он: "объясняет" системе, как именно нужно работать с тем или иным устройством. Одно не все драйверы устройств в Linux работа­ ют с физически:r,,_1:и устройствами, которые можно увидеть и пощупать. Неко­ торые драйверы являются виртуальными и обеспечивают доступ к функци­ ональным возможностям ядра. Такие виртуальные устройства называются псевдоустройствами. Самые известные из них - генератор случайных чи­ /dev/random и /dev/urandom), "пустое" устройство (/dev/ устройство (/dev/zero) и др. Однако большинство драйверов сел ядра (устройства null), "нулевое" все-таки работают с физическими устройствами. 14.2. Модули ядра 14.2.1. Написание Как уже отмечалось ранее, ядро Linux простого модуля является монолитным (выполняется в общем защищенном адресном пространстве). Однако также ядро является и модульным, то есть имеется возможность расширения функционала ядра посредством модулей. Ядро позволяет выполнять динамическую загрузку и удаление кода ядра в процессе работы системы. Соответствующие подпрограммы, данные, а также точки входа и выхода группируются в общий бинарный образ, загружаемый объект ядра, который называется модулем. Поддержка модулей позволяет создать минимальное базовое ядро операционной системы, а все дополнительные воз~ожности и драйверы скомпилировать в качестве загружаемых модулей, т.е. самосто­ ятельных объектов. Модули также позволяют удалять и повторно загружать код ядра, что облегчает отладку, а также' дает возможность загружать драй­ веры по необходимости в ответ на появление новых устройств с функциями "горячего" подключения. '- .... ....... -- ... -. -------------------- ------------: . ---- ---------------------------
я ,, , 1 т1 , i,111, Модуль - ....................... n.1nux это определенным образом написанная программа. Попробуем написать модуль самостоятельно. В лист. 14.1 приведен "пустой" шаблон, который ничего не делает, но вы можете использовать его для на­ писания собственного модуля ядра. Листинг 14.1. Шаблон модуля ядра Linux #include <linux/init . h> #include <linux/module . h> #include <linux/kernel . h> /* * hello_init - функция инициализации , вызывается * В случае успешной загрузки модуля возвращает * и ненулев ое значение в противном случае . при загрузке модуля . значение нуль , */ static int hello_ init(void) { printk(KERN_ALERT " Init . \n "); return О; /* * hello_exit - функция завершения , */ static void hello_exit(void) вызывается при выгрузке модуля . printk(KERN_ALERT "Exiting!\n " ) ; } module_init(hello_init) ; module_exit(hello_exit); MODULE_ LICENSE( "GPL " ) ; MODULE_AUTHOR( " Shakespeare " ); MODULE_DESCRIPTION( " Hello , World! " ) ; Функция hello_init() регистрируется с помощью макроса module_init() в ка­ честве точки входа в модуль. Она вызывается ядром при загрузке модуля. Вызов module_init() - это не вызов функции, а макрос, который устанав­ ливает значение своего параметра в качестве функции инициализации для текущего модуля. Все функции инициализации должны соответствовать прототипу: int my_i nit(void) ; . . ..----------. -------------------------. ----------. ----. ---•---. ----~ --.. --. ---. -- -·
1J1a 11a 14. n.1nux ................. . Ус I poiic I ЩI 11 MOJtYJ III Поскольку функция инициализации редко вызывается за пределами модуля, ее обычно не нужно экспортировать за пределы видимости файла и можно объявить с ключевым словом static. Функции инициализации возвращают значение типа int. Если инициализа­ ция (или то, что делает функция инициализации) прошла успешно, то функ­ ция должна возвратить нулевое значение. В случае ошибки функция должна прекратить выполняемые действия и возвратить ненулевое значение. В рассмотренном нами случае эта функция просто выводит сообщение и возвращает нулевое значение. В реальных модулях функция инициализа­ ции регистрирует ресурсы, инициализирует работу оборудования, выделяет структуры данных и т.д. Если рассматриваемый файл будет статически ском­ пилирован в образ ядра, то функция инициализации помещается в этот образ и будет вызвана при загрузке ядра. Точка выхода из модуля регистрируется с помощью макроса module_exit(). В данном примере мы зарегистрировали в качестве точки выхода функцию hello_exit(). Ядро вызывает эту функцию перед удалением модуля из па­ мяти. Как правило , в функции завершения нужно освободить все используемые ресурсы, остановить работу и выполнить аппаратный сброс оборудования, а также выполнить другие необходимые при завершении работы модуля дей­ ствия. Обычно в функции завершения выполняются действия, обратные тем, что были сделаны в функции инициализации и в процессе работы модуля, особенно это относится к освобождению всех ресурсов, оставшихся после работы модуля. После возврата из функции завершения модуль выгружается из памяти. Функция завершения должна соответствовать прототипу void my_exit (void ); Так же как и в случае функции инициализации, ее можно объявить как static. Если этот файл будет скомпилирован в статический обра:з ядра, то данная функция не будет включена в образ и никогда не будет вызвана (так как если нет модуля, то код никогда не может быть удален из памяти). Макрос MODULE_LICENSE() . позволяет указать лицензию на право копи­ рования модуля • .-- - ................... -- -........... --..... -.. -........ -... -........ -............. . .
Ядро [,inux ....................... n.1nux Загрузка в память модуля без лицензии флага tainted GPL приведет к установке в ядре (буквально "запорченный"). Лицензия на право копирования модуля служит двум целям. Во-первых, для информационных целей. Большинство разработчиков ядра считают отчеты об ошибках, в которых установлен флаг tainted, не заслу­ живающими доверия, поскольку это предполагает, что в ядро был загружен бинарный модуль (т.е. такой модуль, который невозможно отлаживать). Во­ вторых, в модулях без лицензии служат "только для Наконец, макрось1 GPL нельзя использовать символы, которые GPL". MODULE_AUTHOR() и MODULE_DESCRIPТION() позволяют указать автора модуля и его короткое описание соответственно. Назначение этих макросов чисто информационное. 14.2.2. Сборка модуля В пределах дерева исходных кодов ядра Первым делом нужно решить , где именно будет находиться модуль в дере­ ве исходных кодов. Драйверы необходимо хранить в подкаталогах каталога drivers/, который находится в корне дерева исходных кодов ядра. В этом ка­ талоге драйверы делятся на классы, типы и собственно на отдельные драй­ веры. Например, символьные устройства находятся в каталоге блочные - в каталоге drivers/Ьlock/, устройства USB - drivers/char/, drivers/ в каталоге usЫ. Эти правила не являются жесткими, поскольку многие устройства при­ надлежат к разным категориям. Например, большинство USВ-устройств яв­ ляются символьными, но они располагаются в каталоге drivers/usЫ, а не в drivers/char/. Несмотря на подобные сложности, такая организация является понятной и четкой, после того, как вы в ней разберетесь. Предположим, вы хотите создать драйвер символьного устройства и сохра­ нить его файлы в подкаталоге drivers/char/. В этом каталоге находится боль­ шое количество исходных файлов на языке С, а также ряд других подката­ логов. Если драйвер имеет всего один или два исходных файла, их можно поместить непосредственно в этот каталог. Если код драйвера состоит из нескольких исходных или других вспомога­ тельных файлов, . . . . . . ...............................................................................
n.inux ................. . то лучше всего создать отдельный подкаталог. Здесь не существует каких­ то жестких правил. Предположим, вы хотите создать отдельный подкаталог. Для определенности предположим, что вы хотите написать драйвер для на­ шего HelloWorld-мoдyля. Следовательно, необходимо создать подкаталог helloworld в каталоге drivers/char/. После этого необходимо добавить новую строку в файл находится в каталоге drivers/char/. Makefile, который Для этого отредактируйте файл drivers/ char/Мakefile и добавьте в него следующую запись: obj-m += helloworld / Эта строка указывает системе построения, что при компиляции модулей необходимо войти в подкаталог helloworld/. Скорее всего, при компиляции драйвера вам потребуется указать отдельный параметр конфигурации, например CONFIG_FISHING_POLE. В этом случае в файл Makefile необходимо добавить строку вида: obj-$(CONFIG FISHING_POLE) += helloworld / И наконец, в каталоге Makefile, drivers/char/helloworld необходимо создать файл содержащий следующую строку: obj-m += helloworld.o Теперь система построения перейдет в каталог fishing.ko из исходного файла fishing.c. helloworld/ и создаст модуль Здесь вас может сбить с толку указан­ ное расширение объектного файла .о, но в результате будет создан модуль с расширением .ko. Как уже говорилось, скорее всего, при компиляции модуля драйвера с числовым программным управлением вам нужно будет указать параметр конфигурации. В таком случае в новый файл Makefile необходимо добавить следующую строку: obj-$(CONFIG FISHING_POLE) += hell o . o • ······-·············-----------·----·-··-·-·---·----·····-··--·----·-·----- ··· -·---811
И , 1ро l . i1111, ....................... t\.iпux Вне дерева исходников ядра Иногда нужно откомпилировать модул ь вне дерева каталогов исходников. Например, вы не хотите перекомпилировать все модули и ждать выполнения команды если вы заметили ошибку в своем драйвере и вам make modules, нужно просто пересобрать один модуль , а не все сразу. Для этого вынесите модуль за пределы дерева исходных кодов ядра и создайте Makefile, в кото­ рый нужно добавить одну строчку : obj -m := hel l oworld . o В результате файл helloworld.c будет скомпилирован в файл helloworld.ko. 1 14.2.3. Установка модулей Скомпилированные модули должf{ы быть инсталлированы в каталог /liЫ modules/вepcия/kemel. Здесь каждый подкаталог каталога kemel/ соответ­ ствует расположению файлов модуля в дереве исходных кодов ядра . Напри­ мер, для версии ядра 5.2.10 скомпилированный модуль драйвера helloworld будет находиться в файле /l iЬ/modules/5 . 2.10/keme l/drivers/char/helloworld. ko, если исходный код находился непосредственно в каталоге drivers/char/. Для _инсталляции скомпилированных модулей в правильные каталоги ис­ пользуется следующая команда: ma ke mod u l e s instal l Разумеется, эту команду необходимо выполнять с правами пользователя 14.2.4. root. Загрузка модул_ей Обычно для загрузки модуля в память используют утилиту insmod. Эта ути­ лита очень простая: она "просит" ядро загрузить в память указанный вами • . .. ....... ..... . ..... .... · · · ·· · · .... ........... .. .................................. .
n..iпux _______ ______ ____ _ модуль. Утилита insmod lтша 14. Yc1poiic1вa 11 '\Ю;t~ш1 не отслеживает зависимости и не выполняет ни­ какой интеллектуальной обработки ошибок. Использовать ее очень просто. Обладая правами пользователя root, нужно ввести команду insmod module.ko где вместо module.ko необходимо указать имя файла модуля, который тре­ буется загрузить . Так, для загрузки модуля управления удочкой выполните следующую команду: insmod helloworld.ko Удалить модуль можно аналогичным образом с помощью утилиты Для этого, обладая правами пользователя root, rmmod. нужно выполнить приведен­ ную ниже команду, в которой вместо параметра module укажите имя загру­ женного в память модуля. rmmod module Например, для удаления модуля управления введите следующую команду: rmmod helloworld 14.3. Разработка сложных модулей 14.3.1. Компиляция модулей из нескольких файлов исходного кода Представим, что наш модуль Hello World был модернизирован и теперь - helloworld.c и helloadds.c. Чтобы состоит из двух файлов исходного кода . откомпилировать модуль из двух файлов и чтобы компилятор понимал, что они относятся к одному модулю, нужно добавить в ' Makefile инструкции : .-. --------------------------- ... --.. --------------- -----------------------------.. .
Я , tро (,i11ux ... ... ................. n.inux obj - m := h ellowo r ld . o hell oworld- objs · = hellowor l d . o helloads.o В этом примере сначала будут скомпилированы файлы helloadds.c, а затем скомпонованы в файл модуля 14.3.2. Зависимости Утилиты работы с модулями ОС и между модулями Linux поддерживают зависимости между модулями . Это означает, что если модуль при загрузке модуля helloworld.c helloworld.ko. mod 1 модуль mod2 mod 1 зависит от модуля mod2, то будет загружен автоматически. Информация о зависимостях между модулями должна быть сгенерирована администратором. В большинстве дистрибутивов ОС • Linux эта информация генерируется автоматически и обновляется при загрузке системы. Для гене­ рации информации о зависимостях между модулями необходимо, обладая правами пользователя root, выполнить приведенную ниже команду. depmod Для быстрого обновления и генерации информации только о более новых модулях, чем сам файл зависимостей , необходимо, обладая правами пользо­ вателя root, выполнить другую d e pmod команду: -А Информация о зависимостях между модулями хранится в файле /liЫ modules/вepcия/modules . dep. 14.3.3. Загрузка модулей с зависимостями Утилита insmod не очень интеллектуальная. Поэтому также существует ути­ лита modprobe, которая позволяет загрузить модуль с учетом зависимостей, • . ... ... . . . . . -- ....... -- ........... -- ....... . ........... . ...... -... .... . .. . ......... .
fliпux ................. . 1тша 14. Ус I рой с I на 11 I\IOJt)'. 111 выполняет проверку и обработку ошибочных ситуаций, позволяет передать модулям параметры конфигурации и обладает другими полезными функци­ ями. Для управления загрузкой и выгрузкой модулей мы настоятельно реко­ мендуем использовать именно ее. Для загрузки модуля в ядро с помощью утилиты пользователя root, modprobe, обладая правами запустите команду: modprobe module [ параметры модуля] где вместо параметра module необходимо указать имя загружаемого модуля. Все следующие далее аргументы интерпретируются как параметры, которые передаются модулю при загрузке. Утилита modprobe пытается загрузить не только указанный модуль, но и все модули, от которых он зависит. Следовательно, это наиболее предпочтитель­ ный механизм загрузки модулей ядра. Утилита modprobe также может использоваться для удаления модулей из ядра. Для этого, обладая правами пользователя root, запустите команду modprobe -r modules где вместо параметра modules нужно указать один или несколько модулей, которые необходимо удалить. В отличие от rmmod, утилита modprobe так­ же удаляет и все модули , от которых зависит указанный модуль, если по­ следние не используются. В справочном руководстве операционной систе­ мы Linux приведен список других , менее распространенных параметров этой команды. . ' ·· · · ·· ·· ···························································· · ············· - 8 8
Глава 15. Управление хранилищем
Ядро l,inux ....................... n.inux В этой главе мы рассмотрим довольно таки важные вещи, имеющие значе­ ние не только для работы ядра - Linux, но и для самой операционной системы подключение нового жесткого диска и его разметка в классическом вари­ анте без всяких менеджеров томов. Также мы рассмотрим - LVM и то, как можно расширить пространство группы томов, например, когда вы увеличи­ ли дисковое пространство виртуального сервера. 15.1. Подключение нового жесткого диска и его разметка Классической программой для разметки жесткого диска в гих операционных системах является программа Windows программа fdisk fdisk. Linux и дру­ Конечно, в той же совсем другая, но названия программ совпадают. Рассмотрим пример использования этой программы. Представим, что мы подключили новый жесткий диск и нам нужно "ввести" его в эксплуатацию. Тренироваться лучше всего в виртуальной машине, особенно, если вы в пер­ вый раз осуществляете разметку диска. Формат вызoвafdisk такой: .. # fdisk <устройство> • ... . .. . . .. . ... . ..... .. . . .. .. .. ..... .. .. .. . ... . . ...... .. .. . . ..... ... . .. ... .. . . .... .
Глава n.inux _________________ _ Да, команду fdisk нужно запускать с правами что новым является устройство 15. root. У11равле11ие хра111ы11111ем Далее мы будем считать, /dev/sdb: # fdisk /dev /sdb Посмотрите на рис. 15.1. Я запустил программу fdisk для нового и неразме­ ченного жесткого диска. Программа сообщила мне, что: • Все и~менения хранятся только в' памяти и не переносятся на жесткий диск до тех пор, пока вы их не запишите. • Устройство не содержало таблицы разделов и была создана таблица раз­ делов DOS (по умолчанию). Рис. • 15.1. Зanycкfdisk для нового жесткого диска Рис. 15.2. Список команд fdisk .---- ------------- ---------------- ----------------- ------------------ ----------- ---111
Я ; {ро Linux ______________ . ________ n..inux Первым делом ознакомимся со списком команд fdisk. Введите команду т для получения справки. Список команд в последних версиях fdisk разбит на группы (рис. Таблица 15.1. 15.2). В таблице 15 .1 приведен список команд fdis·k . Команды программы fdisk Команда Описание Сделать раздел активным. Данный флаг был нужен для а старых версий Windows, которые не могли загружаться с неактивных разделов . Сейчас эта команда попросту не нужна, а в мире ь с Linux - тем более Редактировать вложенную ВSD-метку Применить флаг совместимости с DOS ' d Удалить раздел / Вывести известные типы разделов п Добавить новый раздел р Вывод таблицы разделов t Изменить тип раздела V Проверить таблицу разделов т Вывод справ~. и Изменить единицы измере1щя х Дополнительная функциональность (только для экспертов) w Записать таблицу разделов на диск и выйти q Выход без сохранения изменении - • a:t---------·-·······-··---························-·······-·--···········--····----·
n.iпux .................. . Глава 15. У11равлс11ие Создать новую пустую таблицу разделов g Создать новую пустую таблицу разделов G SGI хра1111 Jшщем GPT (для ОС IRIX) о s Создать новую пустую таблицу разделов DOS Создать новую пустую таблицу разделов Sun Наша задача - создать раздел (или несколько разделов, здесь решать вам) и подмонтировать его (их) к корневой файловой системе. Первым делом выведем таблицу разделов командой р (рис. из рис. 60 15.3, 15.3). Как видно таблица разделов пуста, а размер нашего жесткого диска всего Гб. Corrro,,шl (m l'ог l1elp): р isk /dev/sdb: 60 GiB, 61121509110 bytes, 125829120 s ectors IJ11ils: sect.11гs .,есt.ог size (\(19ic,1l/p/11p;ic,1\): ol' 1 "S12 \ЛI size (miнi111..1nvпpf.irn,,I): l)isklal)f:) t.1Jpe: dos isk i<teнtifier: 0x1fc'?26dB 'urrmaнd (m fог }1е ~,12 htjl,1:s ~,1?. htJt.es / •,1;,: l)1Jt.es ~,.17. l)IJl.es / ~.,1?. lllJt.,:s 1 ) : Рис. 15.3. Пустая таблица разделов Наш диск довольно скромного размера, поэтому программа создала таблицу разделов DOS. Для больших жестких дисков лучше создать табли_цу разде : лов GРТ. Если программа неправильно выбрала тип таблицы разделов или вы хотите изменить его принудительно, введите команду g. Посмотрите на рис. 15.4: я изменил тип таблицы разделов, а затем опять отобразил таблицу разделов. Она по-прежнему пуста, но обратите внимание на ее тип - теперь у нас таблица разделов GРТ. • •••• • ••••••••••• • •• • •••·· · ·• .. ···················· ··· ········ · -········-- · · · ·· · · · · · - I D
Я , tро Linux _____ . _... __________ . __ n..inux Примечание. Таблица разделов GPT (GUID Partition ТаЫе) яв­ Firmware lnterface) стандарта, который был предложен компанией lntel на смену стандарта BIOS. Таблица GPT использует современную систему адресации логических блоков (LBA), а не старую систему CHS (цилиндр-головка-сектор). Но самое главное - это размер раз­ дела. В GPT можно создать раздел размером до 9.4 Збайт (9.4 х 1021 байт), а в MBR - максимальный размер раздела всего 2.2 Тб (2.2 х 1021 байт). ляется частью стандарта 1· flf' (ExtensiЫe l р) • lj 1 11rr,n.11нi (m !rт,,te,I ,, 11ew Cl'T Ji,;kl,,beJ ((;IJID: 1пrr,n.,щl r.m fш· !,с EFI J,clp) ,:')'J[11E11(1В'J 1ZE6 'J1H C:l'JВCШ,f:'IDП). р isk /dev/sdb: 60 GiB, 61121509110 bytes, 125829120 sectors of 1 • ',12 ',12 Ьчtс•; i:c•· ( lоч iс,,1/рJнгiи, 1 J: ',12 hчtes / ~,1/ btJte:; 1"11 si::c 'mi11irrttrrvoptim,1I). ~,1? Ь')1.1::; / ',12 h>Jte; i•, : k 1" J,,· 1 Сч1н· i1 р t. Pi·k i~eнt.ilicr·: ?Э'Л:4![11AB'J·12Ef,-'J11Г·C:J'JDCИl,E'IDE3 :111 i t.<; ·:,:, t,,r• ,,,т1пr ... iorr,n.ш,t lm f'11r J1elp): Рис. 15.4. Изменение таблицы разделов Настало время создать раздел. Введите команду п. Программа попросит вас ввести (рис. • 15.5): Номер раздела - это первый раздел , поэтому введите 1. В принципе, ког­ да вы будете создавать второй раздел , программа автоматически предло­ жит вам ввести номер 2. • Первый сектор раздела. Просто нажмите Enter - программа автомати­ чески предложит правильный вариант. • Последний сектор раздела . Если вы хотите создать раздел на весь жест­ кий диск (то есть использовать все доступное пространство), тогда просто нажмите Enter. В противном случае укажите размер раздела. Проще всего это сделать, используя модификаторы +Ми для создания раздела размером ... 30 +G, например, Гб укажите +З ОG . Если у вас очень большой жесткий диск, где пространство измеряется терабайтами, ис­ пользуйте модификатор Т, например, + 1Т. . . -- ---- -- .. -- .. --. -- --. -- -. --- . ------- -.. --.. ---. --------. ----. ---. -- ---- --. -- _,
Глава t'tinux _________________ •__ orrwn.•1111 ',11 ·" (m t I f J он t IJ 1 'f'I f 11г 1н· 1111ml)t"1 t111 ,1•( 101, 1 р) 11 1 1 ?.В, (1t·f ,н~ lt 1) ( <1 11.-1.J ))t\i'f 1t 1011 ortnt.ннt (m f11г 1 of ltJpc Управление храншшщем 1 i/H1B 1/.'1B7'J0H6, (lt•f~н•lt ~·и1в) •'Р( tor, ос н 1z,·{K,M,(,,'I ,Г} (%И4Н r1·,,tt>(l 15. '(.~н11л f 1/'Jili""ЩIJf,, 11c~,ц,tt·m' (ннi of 1l1•f<щJI ,,1zc 1/',Н,,:'<IШН,) (}И t,tH "' lн"lp) Рис. 15.5. Создание иового раздела Программа сообщит вам, что один раздел создан. Также будет сообщен раз­ мер разде~а . По умолчанию тип раздела filesystem). t <номер - файловая система Linux (Linux Если вы хотите изменить тип раздела, введите команду: раздела> Например: t 1 Рис. 15.6. Подсказка по типу раздела Далее нужно или ввести код типа раздела или ввести команду подсказки (рис. • L для вывода 15.6) . .----.. --. . -. -------. -. ---........ -----.. -. ---..... --·. -. -.. ---.. --. ---.. --- . ---... .
Ядро Linux _______________________ (linux Проблема вся в том, что нет способа постраничного просмотра типов раз­ дело в , . а все они н~ помещаются на одном экране. Поэтому все равно при­ дется обращаться к документации. Однако в большинстве случаев изменять ти п раздела не нужно, поскольку при создании раздела он создается уже нужного типа . Исключение может возникнуть разве что для раздел а подкач­ ки (Linux swap ). Его код - 82. Если вы передумали менять тип раздела, просто нажмите Enter. Теперь введите р для просмотра нашей таблицы раздел ов. Всегда просматривайте таблицу перед ее записью . После этого введите команду изменений и выход~ из программы (рис. Рис. 15. 7. Весь w для сохранения 15.7). сеанс разметки диска: от создания таблицы разделов до записи изменений Создать раздел мало. Нужно еще создать файловую систему. Не будем ни­ чего выдумывать и создадим стандартную файловую систему ext4 командой mkfs.ext4: # mkfs . ext4 /dev/sdЫ • а:а - ------.---.---.. ------. -----.--.. --------.---.. ---.--. -----.--. -----.---.. ------.
Глава n..inux .................. . 15 . У11равJ 1е11ие Результат выполнения этой команды приведен на рис. Рис. 15.8. хра11ш1ищем 15.8. Создание файловой системы и монтирование жесткого диска После этого нужно создать точку монтирования для нового раздела и под­ монтировать раздел (название точки монтирования можете изменить по сво­ ему усмотрению): # mkdir /mnt/sdЫ # mount /dev/sdЫ # 1s /mnt / sdЫ /mnt/sdЫ Почти все готово. Осталось только добавить запись. в /etc/fstab для автомати­ ческого монтирования созданного раздела: /dev/sdЫ /mnt/sdЫ ex t4 defaults 1 1 Вот теперь можно приступать к использованию нового жесткого диска . • .. ---.. - .. ---... -... -.... -.. --... --....... -.... -... -.... -· .. -... --... -... --... -.... .
Ядро Linux 15.2. _______________________ n..inux Менеджер логических томов 15.2.1. Введение в LVM Впервые менеджер логических томов (LVM, Logical Volume Manager) LVM 1), но более активно он стал применяться только в дистрибутивах с ядром 2.6 (уже вторая версия LVM 2). появился в ядре 2.4 (его первая версия Некоторые современные дистрибутивы используют создают пулы LVM, LVM в некоторых же чанию. Чтобы понять, нужен ли LVM даже не вам LVM, нужно по умолчанию и установлен по умол­ разобраться, что это такое. В этой части главы все будет изложено максимально доступно, так что бояться использовать LVM не стоит. В тоже время, если вам необхо­ димы точные академические определения и дополнительная информация , обратитесь к Linux LVM Howto (http://tldp.org/HOWTO/LVM-HOWTO/), в котором много технических подробностей (если они вам нужны) и не совсем все сразу понятно. LVM - это дополнительный уровень абстракции над аппаратными сред­ ствами, позволяющий собрать вместе несколько дисков в один логический диск, а затем разбить его так, как вам хочется. Примеров использования LVM множество. Самый простой из них - объединение нескольких небольших дисков в один диск большего размера. Например, вам досталось даром (или почти даром) • несколько SSD-дис·ков небольшого размера, скажем, по ка, чтобы получить один 128 Гб и вы хотите объединить эти 2-3 большой диск 256-384 Гб. дис­ Второй пример тоже часто распространен. Представим , что система у вас установлена на небольшом диске, пусть даже на том же SSD-диске размером 80 Гб. Для Linux такой объем вполне достаточен, но рано или поздно сво­ бодное место закончится (все зависит от файлов, с которыми вы работаете). Вы покупаете диск большего размера, скажем, на 500 Гб или даже на 1 Тб. Но система уже установлена и переустанавливать ее не хочется. Что делать? Здесь вам поможет LVM. Первый приведенный мною пример ( объединение трех дисков во время установки) слишком тривиален и с ним справится любой, даже самый на­ чинающий пользователь -просто во время установки нужно выбрать LVM • &1---------------------------------------------------------------------------------·
f'liпux __________________ _ l ; iaвa 15 . У11равлс1111с хра11или1щ•м (если, конечно , дистрибутив его поддерживает) и выбрать диски, которые вы объединяете в группу (пул) . Второй пример более сложный только за счет того, что система уже уста­ новлена, и мы договорились , что переустанавливать ее не будем. Поэтому он и заслуживает рассмотрения в этой главе, а дополнительную информацию вы сможете найти в Linux LVM Howto, ссылка на который была приведена ранее. 15.2.2. Уровни абстракции LVM Прежде, чем перейти к рассмотрению практической стороны вопроса, нуж­ но разобраться с тремя уровнями абстракции, с которыми вам придется столкнуться в • LVM. Вот эти уровни: физические тома. Это могут быть разделы или PV (Physica\ Volume) - целые , еще не размеченные д иски . группа томов. Физические тома объединяются в • VG (Vo\ume Group) - группу и создается единый диск , который вы можете разбить так, как вам хочется . • LV (Logical Volume) диска (VG), который вы логический раздел. Это раздел нашего единого можете отформатировать в любую файло вую си­ стему и использовать так, как вам хочется, как обычный раздел о бычного жесткого диска. Прежде, чем мы продолжим, вы должны знать об одном недостатке. Тома LVM не поддерживаются загрузчиком GRUB . LVM. Поэтому если в ы ис­ пользуете этот устаревший з агрузчик, вам нужно создать отдельный р аздел /Ьооt за пределами /dev/sdal LVM. Грубо говоря , если у вас есть диск /dev/sda, р аздел должен монтироваться к /Ьооt. В него будет установлен загрузчик. Размер этого раздела должен быть небольшой , примерно 100 Мб (вполне будет достаточно) . Что же касается GRUB2, то он нормально загружается с LVM и никакой до­ полнительный раздел создавать не нужно . • . -------- -- -. ----- -- . -- --·-- -- --- . -- --. -------. -- ---- --- . --. ·- --.. --. -- -- ·- ---- --.. . .
Ядро Linux ....................... n.inux 15.2.3. Немного практики Первым делом вам нужно установить пакет lvm2 , если он еще не установ ­ лен. # apt - g e t install lvm2 # yum inst a ll lvm2 Команда установки этого пакета для Fedora/CentOS приведена на всякий случай, так как в большинстве случаев этот пакет в этих дистрибутивах установлен по умолчанию. Будем считать, что система сейчас установлена на монтирован как /. Больше /dev/sdal , который под­ никаких разделов на этом диске не создано - для упрощения примера. Мы подключили второй жесткий диск, который пока еще не разбит. Имя этого диска - /dev/sdb. Если на втором диске не созданы разделы, то создавать их и не нужно. Вы можете сделать все устройство сразу физическим томом есть разделы - (PV). Если на нем не беда, вы можете добавить в группу томов все разделы поочередно . Тратить время на создание разделов не хочется, тем более , что это и не нуж ­ но , поэтому создаем команда PV на все устройство /dev/sdb. Для этого используется pvcreate: # pvc r eate /dev/sdb Phys·ical volume " /dev/sdb " successfully created Теперь нужно создать группу томов с помощью команды vgcreate. Данной команде нужно передать имя группы (пусть это будет ту_vg) и указать фи ­ зическое устройство: # vgc r eate my_vg /dev/sdb Volume group " vgO " successfully created Создаем отдельные логические тома (команда ки (swap) и разделов /home, /tmp и /var. lvcreate) для раздела подкач ­ -L задает размер раздела, Параметр • 8 8 - ················.······························-·························-·······-·
1J 1ана 15. У11раи: 1е11ие n..inux __________________ _ например, -LЗOG задает размер 30 хра1111 . шщем Гб. Параметр -п задает имя логического тома: # # # # lvcreate l vcreate lvc r eate lvcrea t e -n -n -n -n swap - 18G ту- vg home - 1500G my - vg var - 130G ту - vg t mp - 15G my - vg Последний параметр - это имя нашей группы. При желании можно создать отдельный раздел и для но, как правило, программное обеспечение (а /usr, оно в основном устанавливается в обшем, смотрите сами - /usr) в Linux много места не занимает. В никто не мешает ввести еше одну команду lvcreate. Тем более что у нас еще осталось место (если учитывать, что у нас жесткий диск на 1 ТБ). Теперь разберемся , что и где мы создали. Просмотреть информацию по фи­ зическим томам, группам томов и логическим разделам можно с помощью команд pvdisplay, vgdisplay и lvdisplay соответственно. Созданные нами разделы будут храниться в папке /dev/my_ vg/. В л оге вы найдете файлы будут ссылки, а не файлы , home, tmp, var (правда, это этом ката­ но суть от этого не меняется) . Когда созданы логические тома, можно создать на них файловые системы (отформатировать их). Вы можете использовать любую файловую систему, я предпочитаю # # # # # ext4: mkfs . ex t4 - 1 va r · /de v/my_ vg/var mkfs .e x t4 - L h ome /dev/my_vg/home mkfs . ext4 - 1 tmp /dev/my_vg/tmp mkswap - 1 swap /dev/my_vg/swap swapon /dev/my vg/swap Первые три команды создают файловую систему my_ vg/var, /dev/my_ vg/home и /dev/my_ vg/tmp. ext4 на устройствах /dev/ Последние две создают раз­ д ел подкачки и активируют его. Настало время заняться перемешением данных. Суть в следующем - нужно подмонтиррвать пооч ередно новые тома и скопировать в них содержимое /hоше и /var: • •.·-. -·-.. ·.·. -.... --.......................--... -- -·-· .. -·· ..... --... ---...··-... ---ID
Я , 1ро l.inux ..... .... .............. t't1nux # mkdir /mnt/home # mkdir /mn t /va r # mount / dev /my_vg / home / mnt / home # mount /de v/my_ vg/var /mnt /va r # # ер -а ер -а /home/* / mnt / home /var/ * /mnt / var # umount /mnt/home # umount / mnt /vq.r В папку /tmp копировать ничего не нужно . Нужно только изменить права доступа: # # # # mkdir /mnt/ tmp mount / dev / my vg/tmp /mnt/tmp ehmod - R a+rwx /mnt/tmp umount / tmp Почти все. Теперь нужно добавить в вые системы /home, /var, /tmp /dev/mapper /my_vg-h ome /dev/mapper /my_vg - var / dev /mapper / my_vg - tmp /dev/mappe r /my_vg - swap /etc/fstab записи, монтирующие файло~ и указать в нем раздел подкачки: / home /var /tmp п о пе Все готово. Остал ось только ввести команду ext4 relatime ext4 relatime ext4 noat i me . swap SW reboot, 1 1 1 1 о 2 о о чтобы система переза­ грузилась. Корневая файловая система осталась на старом жестком диске (как и /usr), а каталоги , которые занимают больше всего места, были пере­ мещены на логические разделы LVM. • &1---------------------------------------------------------------------------------- ·
J alaBa n..inux ____ .. _.. ____ ..... 15.3. 15 . Y11p.tHJICIIIIC xpaJIIJ J IIIЩCM Расширение LVМ-пространства Предположим, что вы расширили дисковое пространство виртуального сервера. Однако одного расширения в панели управления недостаточно - чтобы система увидела изменения, нужно произвести определенные дей­ ствия. В принципе, задачу расширения пространства сервера можно было решить иначе, например, добавить еще один виртуальный жесткий диск, а дальше или использовать классический способ или же добавить диск в группу ТО!'._ЮВ - все зависит от того, как настроена операционная система виртуального сервера. Но случилось то, что случилось - вы уже расшири­ ли жесткий диск, а вернуть ресурсы в пул, как правило, нельзя. Поэтому рассмотрим процедуру расширения виртуального диска. Первым делом, посмотрим, сколько сейчас дискового пространства доступ­ но. Для этого используется уже известная команда df с параметром -h, чтобы вывод был в удобочитаемом формате: df -h Рис.15.9. Команда df-h На данный момент общий размер группы томов составляет 19 /dev/mapper/vgroup 1-root Гб . Однако мы расширили диск и теперь нам нужно расши­ рить размер этой группы томов до полного размера диска. Чтобы система увидели новый объем жесткого диска, нужно пересканиро­ вать аппаратную конфигурацию. Для этого мы будем использовать следую­ щую команду: • .. .. ... . .. . ---- ..... ........................... .................................... .
Ядро Linux e cho 1 > ....................... t\.inux /sys/Ыock/sda/device/rescan Запустите утилиту parted (используется для работы с разделами диска): parted Введите команду р для просмотра имеющихся разделов (рис. ните номер раздела 1 который мы будем расширять (2) 15.10). Запом­ и новый размер диска (42.9GB). Рис. 15.10. Текущая таблица разделов Запустим команду изменения раздела: resizepart Укажем номер раздела : Partiti on number? 2 ... • . - -. --. -. ---- -. -. --. -. --------- ---·-. -.. ---. ---.. ---. ----. - ------. ---..• ------ -. -- .
n.iпux ..... ............. . А затем - Глава 15 . УправJ 1с1111с xpa1111 J111111t'\I конец раздела - нужно указать как раз то самое значение 42.9GB - именно так, без пробелов . ootic:. ubuntu1804.,.,,# echo 1 > /sys/Ыock/sda/device/rescan rootle.'ubuntu1804: .... # parted NU Parted 3.2 1 sing /dev'/sda Туре ,Jelcome tc GNU Parted: 'help' to vie~v а list of commands. ( parted I р 1odel: vr,11,,are Virtual disk (scsi) isk /de1.,'sda: 42.9GB ector si:e (logical.'physical): 5128/5126 artition ТаЫе: msdos isk Flags: Jumber 1 2 Start 10.i9kB 1000118 End 10001•18 21. 5G8 Size 999f18 20. 5GB Туре File system primary primary ext4 Flags boot lvm {parted) resi:epart artition number? 2 nd' [21.SGB]' 42.9GB (partedi quit nformat ion; You may need to update / etc /f s tab. root(41Ubuntul804: -.,# 1 Рис. Введите команду 15.11. Из.менение размера раздела quit для выхода из parted. Parted сделал свою работу. Оста­ лось сообщить ядру об изменениях размера: pvresize / dev / sda2 Physical volume " / dev/sda2 " changed 1 physical volume(s) resized / О physical volume(s) not resized Расширим логический том: lvextend -r - 1 +100 %FREE /dev/mapper /vg r oup l - root По окончанию работ введем df - h чтобы убедиться, что дисковое простран­ ство расширилось. Посмотрите на рис. 15 .12. На нем результат выполнения команд pvresize, lvextend и df Последний вывод сообщает нам, что размер группы томов vgroup 1-root теперь составляет 41 Гб. Мы успешно расширили том до ново.о размера . ············································································· ····· -l!lil
Я11ро Linux root(Clubuntu1804: .... # _......... _____________ rlinux pvresi:e /dev/sda2 Physical volume "/dev/sda2" changed 1 physical volume(s) resized; 0 physical volume(s) not resi:ed root{aiubuntu1804: ... # lvextend -r -1 +100%FREE /dev/mapper/\,groupl-root Size of logical volume vgroupl/root changed from 18.11 GiB (4637 e)(_tentsJ to <38.07 GiB (9745 ext ts). Logical \·olume vgroupl; root succes-:.full:.; resized. agcount=12, agsi:e=40064€ sects::=512 attr=2, projid32Ьit=l eta-Clata=1 de\' /mapper, vgroupl root isi:e:::512 crc=l Ьlks finobt:::l spinodes=0 rmapbt=0 reflin~=0 bsizec4096 Ьlocksc4748288, imaxpctc25 suni t=0 swidthc0 Ьlks naming =version ascii-ci:::0 ft;,pe:;;l bsi:ec4096 log =internal bsi zec4096 Ыocks:::2560, \'ersion:;;2 sectsz:;;512 sunit::.0 ьН:s, lazy-count:;;1 realtime =попе exts::;;4096 Ыocks:;;0, rtextents:;;0 data Ыocks changed from 4748288 to 9978880 root(Фubuntu1804: .... # df -Н Filesystem Si:e Used Av·ail Use¾ l·iounted on udev 1. бG 0 1.бG 0% /dev ~pfs 315r·i 4 . sr.1 ЗllM 2% /run / ~e_v/mapper /\•groupl- root 41G 2. ЗG 396 6% tmpfs 0 1.6G 1. бG 0% /de\r/shm mpfs 5. Зfi 0% /runilock 0 5. Зf1 tmpfs 1. бG 0 1.6G 0% /sys/fs/cgroup /dev/sdal 967f\ 147[1 75411 17% /boot mpfs 31511 0% /run/user/0 0 315fi rootlalubuntul804: --.# data Рис.15.12. Том расширен ... • - ------ -. -- --. ---. -------. ---- -------- •. ---. ---------------- ----------- ----- -. ---. •
Приложение 1. Файлы к·онфиrурации Linux·
....................... ft.iпux Пl.1. Конфигурационные файлы Чтобы эффективно настраивать и ядро , и систему Linux, нужно ориентиро­ ваться в содержимом конфигурационного каталога. Если загляните в /etc, то кроме подкаталогов в нем вы обнаружите и файлы, которые находятся не­ посредственно в /etc. Описание этих файлов приведено в таблице Пl .1. Со­ держимое каталога может отличаться в зависимости от используемого дис­ трибутива и установленного программного обеспечения. Но общая картина будет примерно одинаковой во всех дистрибутивах. Таблица Пl.1. Файлы из каталога Файл /etc Описание Конфигурация цвета для утилиты DIR- COLORS GREP- COLORS ls. Здесь вы мо- жете указать, каким цветом будут выводиться каталоги, файлы, ссылки и т.д. Конфигурация цвета для утилиты grep • 11111 ·. -------.----.-----------.----.----.------.--.-----.... -... -........ --.. ---.. --..
1Iри л ожение 1. Файлы n..inux _________________ _ ко11фш )' ращш l,inux Содержит параметры для корректировки аппарат- adjtime ных часов База данных псевдонимов для почтовых агентов aliases (МТА) Содержит пользователем , которым запрещено использовать планировщик at.deny at. Дополнительная ин- формация доступна в man at Конфигурация (таблица расписания) планировщика anacrontab anacron Глобальный файл конфигурации оболочки bash. Локальные файлы конфигурации находятся в до- bash.bashrc машнем каталоге каждого пользователя Содержит ключи для DNS-cepвepa Ьind9 Ьind.keys Содержит список номеров портов в диапазоне от 600 до 1024, которые не могут быть использованы Ьindresvport. Ыасk- Ыndresvport, который обычно вызывается list службами. По умолчанию запрещены порты 631,636,664, 774,921,993 и 995, IRC623, которые исполь- зуются различными сетевыми службами Список пользовател•ей, которым запрещено исполь- cron.deny зовать Таблица расписания демона crontab crond Конфигурация NТР (сервер времени) crony* • cron Файл конфигурации для оболочки С csh.cshrc • • - - - - • - - - - - - - • - - - • - - - - - • - - •• - - - • - - - • - • - - Shell о - - - • - - - - - • - - - •• - - •• - - - - - - - - - - •• - - - - • - - - • • • 1111
Ядро Linux _______________________ t'linux Глобальный файл конфигурации для С Shell. Опре- деляет поведения во время регистрации пользова- теля csh.login (login) в системе. На самом деле - это сцена- рий , который запрещено редактировать вручную. Он должен изменяться только время обновления системы. Вместо этого лучше редактировать csh.login.local, /etc/ если вам нужно внести изменения в настройки вашего локального окружения crypttab defaultdomain dhclient.conf dhclientб.conf dhcpd.conf dhcpdб.conf Содержит информацию о зашифрованных томах Содержит доменное имя для сервисов dracut.conf NIS+ Файл конфигурации для DНСР-клиента, версия IPvб Файл конфигурации для DНСР-сервера Файл конфигурации для DНСР-сервера, версия IPvб dialog, опре- деляет цветовую схему диалог~вых интерфейсов, построенных с помощью пакета dnsmasq.conf и Файл конфигурации для DНСР-клиента Конфигурационный файл для пакета dialogrc NIS Конфигурационный файл для dialog dnsma.sq (DNS- маскарадинга) Содержит параметры dracut - средства, initramfs которое формирует • 1111- -------------. ------------. ------. -----------------------. ---. -----------. -. -. ---.
Приложение rlinux _________________ _ drirc 1. Файлы конфигурации Конфигурационный файл для репозитария DRI cvs Файл используется РАМ-модулем environment Linux pam_env. Содер- жит переменные окружения, описанные в виде пар КЛЮЧ=ЗНАЧЕНИЕ, по одной паре в одной строке Параметры esd.conf EsounD (Enlightened Sound Daemon), который используется для смешивания вместе не- которых цифровых аудио потоков для проигрывания на одиночном устройстве Содержит 48-битные Ethemet-aдpeca и соответству- ethers ющие им IР-адреса или имена узлов. Может использоваться некоторыми сетевыми службами для разрешения МАС-адресов в IР-адреса exports Содержит список экспортируемых файловых систем Информация о релизе fedora-re\ease F edora Информационный файл, содержит некоторые ха- filesystems рактеристики и атрибуты файловых систем . В нем нет ничего особенно интересного Содержит список файловых систем, которые будут fstab монтироваться автоматически при загрузке системы Список пользователей, которые НЕ могут войти в систему по ftpusers ля root FTP. Среди них вы найдете пользовате- и многие другие системные учетные запи - си, которые используются для сетевых сервисов и обычно обладают повышенными привилегиями • .--------- -- ---.---.. --------.---.. --.-...... -... -.. ----.--.... -.. --.. -- -.. --- .. ---1111
....................... n..inux group Содержит группы пользователей host.conf Задает порядок разрешения доменных имен hostname Содержит доменное имя узла Ранее использовался для разрешения IР-адресов в доменные .имена . Сейчас для этого используется система hosts DNS, но вы все равно можете определить в нем некоторые IР-адреса, если ваша сеть не использует DNS или же вам нужно переопределить разрешение для определенного IР-адреса. Обе ситуации в наше время настолько редки, что похожи на что-то из области технической фантастики hosts.* Файл конфигурации локальной сети Если существует файл hushlogins, hushlogins file ~/.hushlogin или /etc/ осуществляется «тихий» вход (это от- ключает проверку e-mail и вывод последнего вре- мени входа и сообщения дня Если существует файл (Message ofDay)). /var/log/lastlog, то выводится время последнего входа в систему idmapd.conf Конфигурация демона idmapd idn.conf Файл конфигурации для idnalias.conf Псевдонимы кодировок для idnkit idnkit • 1111-... -.. -... -... --.-.-.... --... --.. --.. ----.--... --.-.-.. --... -...... -.... -....... -.
~ n.inux ....... ......... . inputrc issue issue.net krb5 .conf ld.so.cache ld.so.conf 1Jrшюжс1111с 1. Фаiiлы "°'1ф111 урации IJnux Позволяет задавать обработку отображения символов в специальных ситуациях . Используется редко Приглашение, которое выводится при входе в си- стему (ссылка на /usr/liЬ/issue) Приглашение, которое выводится при сетевом вхо- де в систему (ссылка на /usr/liЬ/issue.net) Параметры Хэш-версия файла Kerberos ld.so.conf. Создается утилитой ldconfig Настройка динамического связывания во время выполнения Задает параметры преобразования некоторых сим- lesskey волов/клавиш, вы не будете редактировать этот - файл libao.conf libaudit.conf Конфигурация библиотеки libao (обычно дается аудио-драйвер по умолчанию) Конфигурация библиотеки libaudit Контрольные определения для пакета \ogin.defs здесь за- shadow. Например, зде сь можно з адать количество неудачных попыток входа в систему и многие другие параметры • logrotate.conf Задает параметры ротации журналов machine-id Содержит идентификатор машины ·······---------- --- ·--····--·---------- -----····-···------··--····-···-···--··--· -1111
Ядро Linux mail.rc manpath.config mime.types mke2fs.conf - -- - - - - - - - - - - - - - - - - - - - - ainux Файл конфигурации программы Этот файл используется пакетом стройки путей тап и man-db для cat на- Содержит список МIМЕ-типов и соответствующих им расширений файлов Файл конфигурации программы Содержит сообщение дня motd mail mke2fs (Message ofthe Day). В зависимости от настроек системы может выводиться при входе в систему mtools.conf netconfig Данный файл является частью пакета mtools.conf. Файл конфигурации сети. Теперь используется только с кодом ТI-RPC в библиотеке libtirc netgroup Содержит описание конфигурации сетевых групп networks Статическая информация о сетевых именах nfsmount.conf nscd.conf nsswitch.conf Файл конфигурации монтирования Конфигурационный файл для NFS nscd (Name Service Cache) Параметры NSS (Network Service Switch) • 111:1------------------------... -.. ---.. ----.------. ---------------------. --------. ---..
1lrшюжс1111с 1. n.inux ................. . Файл конфигурации сервера времени ntp.conf os-release Фай.1ы ю111ф111 уращш (,i1шх Содержит информацию о релизе: номер версии, кодовое имя и т.д. (ссылка на /usr/liЬ/os-release) База данных паролей passwd Этот файл используется программой permissions ntpd chkstat и кос- венно некоторыми RРМ-скриптами для проверки или установки прав и режимов файлов и каталогов при установке . Этот printcap файл автоматически генерируется cupsd, его не нужно редактировать. Все изменения , внесенные в этот файл, будут потеряны Не изменяйте этот файл во избежание потери изменений во время очередного обновления системы. profile Если вам нужно изменить этот файл, отредактируй- те /etc/profile.local, чтобы установить ваши локаль- ные настройки, например, глобальные псевдонимы, переменные protocols pythonЗstart pythonstart raw • VISUAL и EDIТOR и т.д. Список IР-протоколов Startup-cцeнapий Python 3 для сохранения истории интерпретатора и автодополнения имен То же, что и pythonЗstart, но для старых версий Python Определяет параметры привязки rаw-устройств к блочным устройствам .......-... -.... -....... --"... "... -... -"............. "."-.... "... -... -"."--".. -"-.8111
Я , 11ю l,i1111, rc.splash resolv,conf rpc ....................... n..inux Сценарий, определяющий внешний вид индикатора начальной загрузки Конфигурационный файл для системы разрешения имен Список протоколов удаленного вызова процедур (RPC) rsyncd.conf Файл конфигурации для rsyncd, secrets Пароли screenrc securetty Параметры программы rsyncd screen (менеджер экрана с VTl00/ANSI) эмуляцией терминала Содержит имена устройств терминалов (tty), на ко- торых разрешает вход в систему пользователю ' services root Список служб (сервисов) Пароли из файла /etc/shadow. shadow rsyncd /etc/passwd физически хранятся в Поэтому фактически в /etc/passwd хра- нится список пользователей , а пароли этих пользователей находятся в /etc/shadow, доступ к которому ограничен shells slp.conf smartd.conf Список установленных в системе интерпретаторов Файл конфигурации OpenSLP SPI Файл конфигурации демона smartd 118·....................... ·-···--· -- -···· ............... -- --- ---- -- --.. -- --- --.---... ,.
n.inux _________________ _ 1Iр11ложс1111с 1. Фaii:iм ко11ф111 уращ111 l ,inux Позволяет определить, кому можно использовать sudoers команду sudo Некоторые параметры питания suspend.conf Файл конфигурации sysctl. Кроме этого файла также читает параметры из sysctl.conf conf, /run/sysctl.d/* .conf и sysctl файлов /etc/sysctl.d/*. некоторых других Содержит список терминалов и определяет их тип ttytype , Параметры для пакета usb - modeswitch usb_modeswitch vconsole.conf Конфигурационн·ый файл для виртуальной консоли v1rc Файл конфигурации текстового редактора vi Параметры программы wgetrc xattr.conf wget Задает, как обработать расширенные атрибуты при ' копировании между файлами Пl .2. Подкаталоги с конфигурационными файлами Далее мы «пройдемся» по подкаталогам каталога находится в каждом из них (табл. Пl / etc .2) . /etc с целью выяснить, что Содержимое вашего каталога может отличаться в зависимости от дистрибутива и уже установленных программ . Вполне вероятно, что у вас не будет некоторых каталогов, пред­ ставленных в таблице П 1.2, но будут некоторые другие каталоги , назначение которых можно найти или в справочной системе • Linux, или в Интернете . .-... -.--- -- -- -... --· -- ---- -·-----... -----.---.-- ----- -........ -----···-.... -----·t:1111
V Я , tJ)O l,i1шx Таблица ___ ___ . ________________ t.'t1nux 17.2. Подкаталоги каталога /etc Описание Каталог Содержит файл конфигурации N etworkManager Manager и Network файлы конфигураций сетевых соединений в некоторых дистрибутивах PackageKit - это открытый и свободный на- бор приложений для обеспечения высоко- PackageKit уровневого интерфейса для различных менеджеров пакетов. Этот каталог содержит файлы конфигурации Xll abrt Package~it Параметры графического интерфейса (Х Конфигурация Xl 1 Window) abrtd - демона автоматиче- ских отчетов о сбоях Каталог альтернатив по умолчанию. Файл является частью подсистемы altematives altematives, update- которая обслуживает символи- ческие ссылки, определяющие команды, файлы и каталоги, используемые по умолчанию В этих каталогах находятся конфигураци- онные файлы демона аудита audit и audisp - auditd и его диспетчера событий (audit event dispatcher). Основной конфигурационный файл - /etc/ audit/auditd.conf. В нем задается поведение демона и некоторые настройки, например, расположение журнала по умолчанию /var/ log/audit/audit.log • ~ . . . . . -. ------- ----. ---.. --- ---... ---. -. -. --. --. -. -.. ---. -----. ---------- --------_,
llp11111 ,1, , · 1111 , · 1 «l•a11 . 11,11,1111ф111~р.щ1111 l . i1111, n.1nux ................. . apt bash comletion.d Конфигурация менеджера пакетов apt Параметры автодополнения командной строки для оболочки bash Демон Ьinfmt.d настраивает дополнительЬinfmt.d ные двоичные файлы для выполнения во время загрузки. В этом каталоге находятся его конфигурационные файлы cockpit Конфигурация панели управления Пакет cifs-utils cifs-utils Cockpit содержит средство монти- рования ресурсов общего доступа CIFS в Linux. SMB/ В этом каталоге находятся конфигурационные файлы пакета cifs-utils Содержит файлы, которые загружаются в память одновременно с файлами из катало- crond.d га /var/spool/cron. После этого демон загружает содержимое файла cron /etc/crontab и начинает его обработку Содержат сценарии, которые будут вы- cron.daily, cron.hourly, cron. mounthly, cron.weekly полнены демоном cron, соответственно, ежедневно , ежечасно , ежемесячно и еженедельно Содержит параметры конфигурации систе- cups мы печати CUPS (Common Unix Printing System) В пакете дули cupshelpers python-cupshelpers содержатся моPython, которые помогают создавать приложения и утилиты с использованием Руthоn-интерфейса к CUPS. В этом катало- ге находятся параметры этого пакета • ..... .. .. .. .. . ..... ...... .. . ... . ...... ........ ... .. ... . . .. ..... .. .... ........ ... · · -
Ящю l . i1111x ..................... . . t\.1nux crypto-policies dbus-1 Конфигурация крипта-политик Содержит файлы конфигурации демона dbus-daemon Содержит некоторые параметры по умол- default чанию , например , параметры загрузчика GRUB depmod - программа для создания файла modules.dep и mар-файла . В этом каталоге depmod.d находятся ее файлы конфигурации . Как администратор сервера, вы можете о них просто забыть , они вам не пригодятся dhcp Конфигурация DНСР-сервера dnf Конфигурация менеджера пакетов dracut dracut.conf.d заменяет mkinitrd для создания загрузочной файловой системы в оперативной памяти (ramdisk). Здесь находятся конфигурационные файлы firewalld dnf dracut Конфигурация брандмауэра Содержит конфигурационные файлы под- fonts системы шрифтов. В частности, файл / etc/fonts/fonts .conf описывает каталоги со шрифтами , каталоги с кэшем шрифтов , а также описывает аналоги шрифтов gnupg Содержит конфигурационный файл GnuPg • ID-------------.---.-----------------.-... -.. --................ -............ -... --..
fl.1пux ................. . l lp11 10,1,t:11111: 1 Фaiim.1 1,1111ф111 ур:щ1111 J,i11U\ Содержит файлы, относящиеся к загрузчи• grub.d ку GRUB . Вам не нужно редактировать эти файлы, они предназначены для служебных целей init.d Содержит сценарии системы инициализа• ции Параметры подсистемы маршрутизации. iproute2 Например, могут использоваться для IP· балансировки , то есть объединения нескольких Интернет•каналов в один Параметры lSCSl Параметры Java joe iSCSI Java Содержит конфигурационные файлы тек- стового редактора joe ' jvm, jvm-common Параметры виртуальной машины Содержит файлы с расширением ld.so.conf.d Java conf, ко- торые используются для поиска разделяе- мых библиотек libnl logrotate.d те • Конфигурационные файлы библиотеки libnl Конфигурация средства ротации журналов Файлы конфигурации файлового менеджера Midnight Commander .. --------------------.. -----·: ---------------------------. ---. ----. ---. ---. ------ID
И , tpll l ,illll\ ....................... n.1nux Программа mcelog mcelog позволяет расшифро- вать аппаратные ошибки. Настраивается посредством конфигурационных файлов в каталоге /etc/mcelog программа для добавления и modprobe - удаления модулей из ядра modprobe.d Linux. Соответ- ственно в одноименном подкаталоге ката- лога /etc находятся ее конфигурационные файлы modules-load.d openldap opt Содержит параметры некоторых модулей ядра. По умолчанию в этом каталоге пусто Содержит конфигурационные файлы сервера каталогов OpenLDAP Файлы конфигурации для /opt/ Параметры конфигурации модулей аутен- pam.d тификации РАМ (PluggaЫe Authentication Modules) Параметры программы pkcsl 1 PKCS# 11 (Cryptoki) Содержит список GРG-ключей Plymouth plymouth использу- которые находятся на зашифрованных устройствах pki pkcs 11, емой для управления объектами данных, свободный графический экран загрузки для Linux. Этот каталог содержит его конфигурационные файлы • ................................................................ ......... .... ........ '
1Iр11 . 10жсю1с 1. Фaii ."JЫ n..inux ..... .... : ....... . ~-.:011ф111 уращш Linux Содержит конфигурационные файлы парт кета pm-utils. Пакет pm-utils - это инфра- структура управления питанием нового поколения postfix Конфигурационные файлы почтового агента Файлы конфигурации протокола РРР ррр pptp.d Postfix Файлы конфигурации демона pptpd (про- токол РРТР) Относится к системе миграции между версиями дистрибутива products.d openSUSE. Дополни- тельная информация может быть найдена по ссылке http://doc.opensuse.org/products/ draft/SLESISLES-deployment_sd_ draft/cha. update.s le.html PulseAudio - это звуковой сервер для РОSIХ-систем. Его основное назначение pulse смешивать звуковые потоки от разных приложений, что позволяет нескольким потокам воспроизводиться одновременно. Здесь находятся конфигурационные файлы PulseAudio rc.d rsyslog.d • Ссылка на каталог init.d Конфигурация демона протоколирования rsyslogd ... .... ....... .... . .. -- .. -- .... -....... ----. -...... -.............................. . . .
Я J t po l,i,iux ................ ......... n..inux Различные параметры системы управления пакетами rpm RPM. Обычно файлы из этого каталога не требуют изменения. Дополни- тельную информацию можно получить по адресу samba sasl2 security selinux http: //wiki.opennet.ru/RPM Конфигурационные файлы ' Samba Параметры SASL (Simple Authentication and Security Layer) Еще один параметр конфигурации, относящийся к модулям аутентификации РАМ Содержит файлы конфигурации системы безопасности SELinux При создании новой учетной записи пользователя создается его домашний каталог в каталоге skel /home, при этом в созданный до- машний каталог пользователя копируются файлы из каталога /skel. Все помещенные в этот каталог файлы будут скопированы в созданный домашний каталог ssh ssl Содержит файлы конфигурации клиента и SSH-cepвepa Файлы конфигурации Кроме файла sudoers.d SSH- OpenSSL /etc/sudoers, настройки sudo могут определяться содержимым файлов из каталога /etc/sudoers.d • ....................................... . ... .......................................... j
n.inux ______ __ __ __ _____ _ l lrшюжс111н: 1. Фай J 1ы конфш ~ращш l,i11ux Содержит конфигурационные файлы всей системы. В этом каталоге очень много раз- личных конфигурационных файлов. На- sysconfig пример, в каталоге /etc/sysconfig/network вы найдете конфигурационные файлы сетевых интерфейсов. А в файле clock хранится вы- бранный при установке часовой пояс sysctl.d настраивает параметры ядра при sysctl.d загрузке, здесь находятся его конфигурационные параметры systemd udev Конфигурационные файлы демона systemd Файлы конфигурации и файлы правил ме- неджера устройств udev Конфигурационные файлы пакета wpa_supplicant wpa_ supplicant (обеспечивает поддержку WEP, WPAиWPA2) xdg-open - это независимый пользователь- ский инструмент для настройки приложе- ний рабочего стола по умолчанию. В этом каталоге находятся его конфигурационные xdg файлы. Например, в каталоге autostart находятся /etc/xdg/ все программы, которые могут быть запущены автоматически. Однако запускаются лишь те, которым разре- шен запуск_ в определенной сессии Содержит дополнительные файлы конфи- xinetd.d гурации суперсервера xinetd (в современ- ных дистрибутивах не используется) xml • Конфигурационные файлы библиотеки libxml ·-------------·-····-------·---·--·-··-···---··-····-··--·························-ID
Приложение 2. Командный интерпретатор bash
Ядро l.iш1x ....................... rl.inux В этом приложении мы рассмотрим командный интерпретатор bash. Это больше, чем просто средство для ввода команд, у него есть свои параметры и свои команды. Да, да , именно команды. На (подобно тому, как в MS DOS подобны языку программирования т.д . Знание возможностей bash вания операционной системы bash можно написать сценарии создавались ВАТ-файлы). Возможности - bash есть управляющие структуры, циклы и не менее важно для полноценного использо­ Linux, чем использование функций ядра или рабочего окружения. Обо всем этом мы поговорим в данной главе. П2 .1 . Настройка bash bash - это самая популярная командная оболочка (командный интерпрета­ Linux. Основное предназначение bash - выполнение команд, ·введен­ ных пользователем. Пользователь вводит команду и bash ищет программу, тор) соответствующую команде , в каталогах , указанных в переменной окруже­ ния РАТН . Если такая программа найдена, то bash запускает ее и передает ей введенные пользователем параметры. В противном случае выводится сообщение о невозможности выпол нения команды. • 111---.. ---.. ----. --......... ---- ----- ------........................................ .
n.inux ................. . Интерпретатор bash - 1/р11 J южс1111с 2. Комащщый ,ш I t.•pщ>t' 1 а I ор lms/1 не единственная оболочка, доступная в вашей систе­ ме . Список доступных оболочек доступен в файле случаев по умолчанию используется /etc/shells. В большинстве bash. Файл /etc/profile содержит глобальные настройки bash, он влияет на всю - на каждую запущенную оболочку. Обычно /etc/profile не нужда­ в изменении, а при необходимости изменить параметры bash редакти­ систему ется руют один из файлов: обрабатывается при каждом входе в систему; • ~/.bash_profile • ~/.bashrc - обрабатывается при каждом запуске дочерней оболочки; • ~/.bash_logout- обрабатывается Файл ~/.bash_profile при выходе из системы. часто не существует, а если и существует, то в нем есть всего одна строка: source ~/ . bashrc Данная строка означает, что нужно прочитать файл .bashrc. Поэтому будем .bashrc. Но помните, считать основным конфигурационным файлом файл что он влияет на оболочку текущего пользователя (такой файл находится в домашнем каталоге каждого пользователя, не забываем: "~" означает до­ машний каталог). Если же вдруг понадобится задать параметры, которые повлияют на всех пользователей, то нужно редактировать файл Файл .bash_history /etc/profile. (тоже находится в домашнем каталоге) содержит исто­ рию команд, введенных пользователем. Здесь вы можете просмотреть свои же команды , которые вы накануне вводили. Конфигурация bash хранится в файле .bashrc. Обычно в этом файле задают­ ся псевдонимы команд, определяется внешний вид приглашения командной строки, задаются значения переменных окружения. Псевдонимы команд задаются с помощью команды alias, вот несколько при­ меров: alias h= ' fc - 1 ' alias ll='ls - laFo ' • .... ... . ... . .. . -........................... -.............. -....................... -
Я . 1ро Li1111x ....................... n..iпux alias l= ' ls -1' alias g= ' egrep -i' Псевдонимы работают просто: при вводе команды полнена команда ! на самом деле будет вы­ ls -!. Теперь рассмотрим пример изменения приглашения командной строки. Гло­ бальная переменная PS 1 отвечает за внешний вид командной строки. По умолчанию командная строка имеет формат: пользователь@к омпьют ер : рабочий_каталог Значение PS 1 при этом будет: PS1= ' \ u@ \ h: \ w$ ' В табл. П2.1 приведены допустимые модификаторы командной строки. Таблица П2.1. Модификаторы командной строки Модификатор \а АSСП-символ звонка (код использовать - 07). Не рекомендуется его очень скоро начнет раздражать \d Дата в формате "день недели, месяц, число" \h Имя компьютера до первой точки \Н Полное имя компьютера \j .. Описание Количество задач, запущенных в оболочке в данное время \! Название терминала \п Символ новой строки • .. .. .... ....... ..... .... ---- ........... . .... -- --- · ··- -··· ...... .. . .. . .. .. .. .. .... .
l lp11 110,l,L'I IIIL' t.\.1nux ................. . 2 J(нм:111 , 1111.111 1111 н·р11рt• 1:1111)1 lr Возврат каретки 1s Название оболочки lt Время в 24-часовом формате (ЧЧ: ММ: СС) IT Время в 12-часовом формате (ЧЧ: ММ: СС) 1@ Время в 12-часовом формате (АМ/РМ) lu Имя пользователя Версия lv IV Версия bash вариант) (полная версия: номер релиза, номер патча) Текущий каталог (полный путь) lw IW bash (сокращенный lu/\/1 Текущий каталог (только название каталога, без пути) 1/ Номер команды в истории 1# Системный номер команды Если UID пользователя равен О, будет выведен символ 1$ #, иначе - символ$ 11 Обратный слэш $ () Подстановка внешней команды Вот пример альтернативного приглашения командной строки: PSl= ' [\u@\h] • $ (date + %m/% d /% y) \$ ' .. . -.. --... -... --.... --. ---.. -... --. .. -... --... -... --....... --.................... . . .
Ядро l,iщ1x ....................... n.1nux Вид приглашения будет такой: [denis@hosting] 08/04/19 $ В квадратных скобках выводится имя пользователя и имя компьютера, за­ тем используется конструкция $() для подстановки даты в нужном нам фор­ мате и символ приглашения, который изменяется в зависимости от иденти­ фикатора пользователя. Установить переменную окружения можно с помощью команды export, что будет показано позже . П2.2. Зачем нужны сценарии bas/1 Представим, что нам нужно выполнить резервное копирование всех важных файлов, для чего создать архивы каталогов /etc, /home и /usr. Понятно, что понадобятся три команды вида: tar - cvjf имя ~pxивa . tar . bz2 катало г Затем нам нужно записать все эти три файла на программы для прожига DVD с помощью любой DVD. Если выполнять данную операцию раз в месяц (или хотя бы раз в неделю), то ничего страшного . Но представьте, что вам.нужно делать это каждый день или даже несколько раз в день? Думаю, такая рутинная работа вам быстро надоест. А ведь можно написать сценарий, который сам будет создавать ре­ зервные копии, и записывать их на вить чистый DVD DVD! Все, что вам нужно, - это вста­ перед запуском сценария. Можно пойти и иным путем: написать сценарий, который будет делать резервные копии системных каталогов, и записывать их на другой раздел жесткого диска. Ведь не секрет, что резервные копии делаются не только на случай сбоя системы, но и для защиты от некорректного изменения данных пользователем. Помню, удалил важную тему форума и попросил своего хо­ стинг-провайдера сделать откат. Я был приятно удивлен, когда мне предо­ ставили на выбор три резервные копии - осталось лишь выбрать наиболее .... - ----.. ·-· -. -···· ... -· -- . ·- ----- .. --·· .. ..... -... --· ..................... --··-. ' .
f.l1nux .. .. . ....... . . . .. . l lp11 J южc1111c 2. Koм:111 1 1111,iii 11111 t·рщн· 1 :11щ> l1t1.\l1 подходящую . Не думаете же вы , что администраторы провайдера только и занимались тем , что три раза в день копировали домашние каталоги пользо­ вателей? Поэтому, автоматиз ация - штука полезная , и любому администра­ тору нужно знать, как автоматизировать свою рутинную работу. П2.3. Сценарий "Привет, мир!" По традиции напишем первый сценарий , выводящий всем известную фразу: Hello, world!. Для редактирования сценариев вы можете использовать люби­ мый текстовый редактор , например , nano или ее (листинг П2.1) . Листинг ПР2.1 . П е рв ый сцена рий # ! /Ьin/bash echo " Привет , мир! " Первая строка нашего сценария - это указание , что он · должен быть обра­ ботан программой /Ьin/Ьash . Обратите внимание: если между #и ! окажется пробел, то данная директива не сработает, поскольку будет воспринята как обычный комментарий . Комментарии начинаются, как вы уже наверня ка знаете, с решетки : # Комментарий Втор&я строка - это оператор сценарий под именем $ chmod +х hello echo , выводящий нашу строку. Сохраните и введите команду: hello Для запуска сценария введите команду : . /hello • ................................................................................... . .
И , tpct l , illll\ ........ . .............. n.,nux На экране вы увидите строку: Привет , мир ! Чтобы вводить для запуска сценария просто hello (без ./), сценарий нужно скопировать в каталог /usr/Ьin (точнее, в любой каталог из переменной окру­ жения РАТН): # ер ./hello /u?r/bin П2.4. Переменные в сценариях В любом серьезном сценарии вы не обойдетесь без использования перемен­ ных . Переменные можно объявлять в любом месте сценария, но до места их первого применения . Рекомендуется объявлять переменные в самом начале сценария, чтобы потом не искать, где вы объявили ту или иную переменную. Для объявления переменной используется следующая конструкция: переменная=з н ачение Пример объявления переменной: ADDRESS=firma . ru echo $ADDRESS При объявлении переменной знак доллара не ставится, но он обязателен при использовании переменной. Также при объявлении переменной не должно быть пробелов до и после знака=. Значение для переменной указывать вручную не обязательно - его можно прочитать с клавиатуры : ' read ADDRESS • ID-·········-·-------- --··--· -----·--·--·······-······-·-··········-········ - ·- · -·--·
l lp11 n.1nux . ................ . io ,1,L· 11 11L· .' К11м:111 , щ1.11i 1111н·р11ре1а111р /11/\/1 или со стандартного вывода программы: ADDRESS='hostname' Чтение значения переменной с клавиатуры осуществляется с помощью инструкции read. При этом указывать символ доллара не нужно. Вторая команда устанавливает в качестве значения переменной команды В ADDRESS вывод hostname. Linux часто используются переменные окружения . Это специальные пере­ менные, содержащие служебные данные. Вот примеры некоторых часто ис­ пользуемых переменных окружения : • BASH - полный путь до исполняемого файла командной оболочки • BASH_VERSION - версия bssh; bash; • НОМЕ-домашний каталог пользователя, который запустил сценарий; • НОSТNАМЕ • RANDOM • OSTYPE • PWD • PS 1 - имя компьютера; случайное число в диапазоне от О до 32 767; тип операционной системы; текущий каталог; строка приглашения; • UID - ID • USER - - пользователя, который запустил сценарий; имя пользователя . Для установки собственной переменной окружения используется команда export: # присваиваем переменной значение $ADDRESS=firma.ru # экспортируем переменную - делаем ее переменной окружения # после этого переменная ADDRESS будет доступна в других сценариях export $ADDRESS • .. . . . . . --.. .... ·.--.. --....... -..................... ---. ---.. -... -.... --.. -. -. -..... .
И , 11ю l , i1111, ....................... r.L1nux П2.5. Передаем параметры сценарию О~ень часто сценариям нужно передавать различные параметры , например, режим работы или имя файла/каталога. Для передачи параметров использу­ ются следующие специальные переменные: • $0 - содержит имя сценария; • $n - содержит значение параметра (п • $# - позволяет узнать количество параметров, которые были переданы. - номер параметра); Рассмотрим небольшой пример обработки параметров сценария . Я пони­ маю, что конструкцию case-esac вы, возможно, не знаете, но общий принцип должен быть понятен (листинг П2.2). Листинг П2.2. Получение параметров сценария # # Сценарий имя должен сценария вызываться так : параметр # Анализируем первый параметр case " $1 " in start) # Действия при получении параметра start echo " Запускаемся ... " stop) # Действия при получении параметра stop echo " Завершаем работу ... " *) # Действия в остальных случаях # Выводим подсказку о том , как нужно использовать # завершаем работу сценария echo " Использовать : $0 {startlstop }" exit 1 сценарий , и esac Думаю, приведенных комментариев достаточно, поэтому подробно рассма­ тривать работу сценария из листинга П2.2 не будем . • • 111- ---·---··--··-·-·--···--··---··-·-·--··---··---·---··- - --------------·---·· - ---·--
11 р11 t\.1nux ................. . •П2.6. 111 ,1,L· 1111 c :' Ксща~щ11ыi1 1111 н•р111н• 1а I нр /1а,/1 Обработка массивов Интерпретатор позволяет использовать массивы. Массивы объявляют­ bash ся подобно переменным. Вот пример объявления массива: ARRAY[O]=l ARRAY[1]=2 Выводим элемент массива : echo $ARRAY[0] П2. 7. Циклы for и while Как и в любом языке программирования , в Мы рассмотрим циклы циклы until и select, for и while, bash можно использовать циклы. bash дос,тупны также хотя вообще в но они приме~яются довольно редко. Синтаксис циклаfоr выглядит так: f or do переменная in список команды done В цикле , при каждой итерации, переменной будет присвоен очередной эле­ мент списка, над которым будут выполнены указанные команды. Чтобы было понятнее, рассмотрим небольшой пример : for n in 1 2 do echo $n ; done • З; ·---------------------------------------------··--------·---··---·----·--·· ·--· --- -
Ищюl,i1111, ........... •............ t\.1nux Обратите внимание: список значений и список команд должны заканчивать­ ся точкой с запятой. Как и следовало ожидать, наш сценарий выведет на экран следующее: 1 2 3 Синтаксис цикла while do while выглядит немного иначе: условие команды done Цикл while выполняется до тех пор, пока истинно заданное условие. Под­ робно об условиях мы поговорим, возможно, чуть позже, а сейчас напишем аналог предыдущего цикла, т. е. нам нужно вывести while, 1, 2 и 3, но с помощью а не for: n=l while [ $n -lt 4 ] do echo " $n " n=$(( $n+l )); done П2.8. Условные операторы В bash доступны два условных оператора: ifи case. Синтаксис оператора iftледующий: if 1 then 1 elif условие 2 then условие команды команды_2 • .....................................................................................
1Iр11 . южсн11с 2. n.1nux ....... .......... . elif условие_N К1ша11 , щыii 11111ер11ре1 а1ор has/1 then команды_N else команды N+l fi Оператор if в bash работает аналогично оператору if в других языках про­ граммирования. Если истинно первое условие, то выполняется первый спи­ сок команд, иначе elif, - проверяется второе условие и т. д. Количество блоков понятно, не- ограничено. Самая ответственная задача - это правильно составить условие. Условия записываются в квадратных скобках. Вот пример записи условий: # Переменная N [ N==l0 ] # Переменная N [ N!=l0 ] 10 не равна 10 Операции сравнения указываются не с помощью привычных знаков > или <, а с помощью следующих выражений: • -lt - меньше; • • -gt - больше; -/е меньше или равно; • - • -ge - больше или равно; • равно (используется вместо=). -eq - Применять данные выражения нужно следующим образом: [ переменная выражение значениеlпеременная] Например: • ··························· ·······················································-
Я , tро l.i1111\ # [ # [ ............. . ......... n.inux N меньше 10 $N - lt 10 ] N ме н ьше А $N - lt $А ] В квадратных скобках вы также можете задать выражения для проверки су­ ществования файла и каталога : • -е файл - условие истинно , если файл существует; • -d каталог • -х файл - С оператором условие истинно , если каталог существует ; условие истинно , если файл является исполняемым . case мы уже немного знакомы , но сейчас рассмотрим его син­ таксис чуть подробнее: cas e переменная in 1) команды_l ,, з начение_N) команды_N ,, значение * ) команды_по esac умолчанию ;; Значение указанной переменной по очереди сравнивается с приведенными значениями (значение_! , .. ., значение_N) . Если есть совпадение, то будут выполнены команды, соответствующие значению. Если совпадений нет, то будут выполнены команды по умолчанию . Пример использования case был приведен в листинге П2 . 2. П2.9. Функции в В bash bash можно использовать функции . Синтаксис объявления функции сле­ дующий: имя • () { список ; • ················.··································································
n.iпux ................. . l lp11 . 1o;кc1111 c ~ К11м:111 , щыii 11111 t·pщ>t· 1 а 111р l1tl\l1 Вот пример объявления и использования функции: list_txt () { echo " Text files in current directory :" 1s * . txt } П2.10. Практические примеры сценариев Проверка прав пользователя Для сценариев , требующих полномочий кой пользователь запустил сценарий. root, сначала нужно проверить , ка­ UID пользователя root всегда равен О. Проверка, является ли пользователь , запустивший сценарий , пользователем root, может выглядеть так , как показано в листинге П2.3. Листинг П2.3. Проверка полномочий пользователя # ! / Ьin / bash ROOT UIQ=0 if [ " $UID " - eq " $ROOT UID " then echo " Root " else echo " Обыч н ый пол ьз ователь " fi exit О Проверка свободного дискового пространства с уведомлением по e-mail Следующий сценарий проверяет свободное дисковое пространство серве­ • ра и отправляет уведомление по e-mail администратору, если осталось ······--------------------------------------·--------···-·-------------·-- ---- ---· •
Я . 1ро l,inux меньше 2000 _______________________ n..inux Мбайт дискового пространства. Сценарий целесообразно за­ пускать через планировщик заданий (например , через cron) с заданной пе­ риодичностью (например , каждый час) . Код сценария приведен в листинге П2.4 . Листинг П2.4. Проверка свободного дискового пространства #!/Ьin/bash # В переменную freespace будет записано свободное пространство # на контролируемом диске - /dev/sdal (в Мбайт) freespace='df - m I grep " /dev/sdal " 1 awk ' {print $4) ' • # Если места на диске< 2000 МЬ , то отправляем п и сьмо администратору if [ $freespace - lt 2000 ] ; then echo " На сервера меньше< 2000 МВ " 1 mail -s " Свободное место заканчивается !" admin@firma . ru fi • 1111- ------------------------. --. -. -----. --- ------. ------. ----------------------- -----.
Приложение 3. Сетевая файловая система NFS
Я , tро l,i1111x ....................... n..1nux ПЗ.1. Вкратце о NFS и установке необходимых пакетов Сетевая файловая система (NFS, Network File System) - старый_, но прове­ ренный способ предоставления доступа к общим файлам. NFS позволяет монтировать файловые системы, которые физически находятся на других компьютерах в вашей локальной сети. Принцип работы NFS прост: на сервере устанавливается демон nfsd, ко­ торый экспортирует файловые системы. NFS-клиент монтирует экспорти­ руемые файловые системы. После монтирования с удаленной файловой системой можно работать, как с локальной - для пользователя ничего не изменится, разве что скорость доступа к файлам будет чуть ниже, поскольку данные ведь передаются по сети. В вашей сети может быть несколько NFS-cepвepoв _и несколько клиентов. По сути, каждый NFS-клиент может выступать и в роли cepвepa, но обычно NFS NFSNFS- используется иначе. Выделяется один NFS-cepвep, который будет экспортировать общую файловую систему, которая может ис­ пользоваться для хранения общих файлов - довольно частый сценарий . • . . ..... ··-. -- ---- ---- - ---- -- . --- --- -. ------- ---- ----··· ............................. .
l lp11 J IOЖClll1C f.t1nux ................. . 1. ('('(('IШSI ф:tii.юв:ш CIICl('M:I ~,.- s Чтобы установить NFS-cepвep и/или NFS-клиент произведите поиск пакета по слову 'nfs'. Далее прочитайте описания пакетов и установите необходи­ мые вам пакеты. Названия пакетов могут отличаться в зависимости от дис­ трибутива. Например, в openSUSE на сервере нужно установить следующие пакеты: • nfs-kernel-se_rver • nfswatch - содержит NFS-cepвep; утилита мониторинга NFS-трафика (можно не устанавливать); • quota-nfs - система дисковых квот для NFS. На клиенте нужно установить только пакет ПЗ.2. Файл В файле nfs-client. /etc/exports /etc/exports прописываются экспортируемые файловые системы. Эти экспортируемые файловые системы могут монтировать клиенты, Об­ щий формат записи в файле файловая_система exports [компьютер ] следующий: (опции) Вот типичный пример: / home / puЫic (rw) / home / templates . (ro) В данном случае каталог /home/puЫic сервера будет доступен NFS-клиентам для чтения и записи (rw), а каталог /home/templates - только для чтения (ro). При желании можно еще и указать узлы, которым будет доступен экспорти­ руемый каталог, например: / home/sharel 192 .1 68.1 . 100 (rw) / home / share2 host . example . com (rw) / home / shareЗ *.example . com (rw) • ················································································· · -
Я д ро l.iпux _______________________ r.linux Здесь первый каталог (/home/share) будет доступен только узлу с IР-адресом 192.168.1 .100, второй каталог - только узлу с доменным именем host. example.com, а третий - всем узлам из домена example.com. Также можно указать целую IР-сеть и ее маску, например: /home/s hare4 192 .1 68:1 . 0/28 (rw) В данном случае получить доступ к /home/share4 смогут лишь первые 16 - от 192.168.1.0 до 192.168.1.15. Компьютеры с IР-адресами 192.168.1.16 и выше не смогут использовать эту файловую систему. IР-адресов Обычно можно обойтись только опциями ro, rw и noaccess. Последняя ис­ пользуется для запрещения доступа к файловой системе. Например, вы хо­ тите запретить узлу 192.168.1.5 доступ к файловой системе: / h ome/share4 192.168.1 .5 (noaccess) Остальные опции NFS приведены в таблице ПЗ .1. Таблица ПЗ.1. Опции экспорта файловой системы в Опция all_squash insecure link absolute link- relative root_squash по _root_squash NFS Описание Преобразует идентификаторы групп и пользователей в анонимные Разрешает запросы с любых портов, см. secure Не изменяет символические ссылки (по умолчанию) Абсолютные ссылки будут преобразованы в относительные Преобразует все запросы от root в запросы от анонимно- го пользователя Разрешает доступ к файловой системе от имени рекомендуется root. Не • 1111-------------------------... --.. --.. --... --------------------. ----.-------. -------,
n.1nux ........ . .... . ... . Принимает з апросы на монтировани е файловой систе­ secure мы только с портов с номерами < может создавать только 1024. Такие порты root, по этому такое соединение считается безопасным. Используется по умолчанию После редактирования файла пустить службу не забудьте перезапустить или за­ /etc/exports nfs: # service nfs start или # service nfs restart ПЗ.3. Использование NFS-клиента Для монтирования сетевой файловой системы используется та же команда mount. Синтаксис вызова команды такой: mount - t n f s сервер : ФС точка_мон т и р о ван ия Вот пример: mount -t nfs 192 . 168 . 1.157 : /home/share /mnt/share Сервер 192.168.1.157 экспортирует файловую монтируем эту файловую систему к каталогу вать на момент вызова команды метр -t, который задает тип mount). систему /home/share. Мы под­ /mnt/share (должен существо­ Также обратите внимание на пара­ файловой системы . Конечно , вы не будете вводить эту команду после каждой перезагрузки . По этому если удаленную файловую систему нужно использовать постоян­ но , лучше прописать ее в файле /etc/fstab: 192 . 168 . 1 . 157 : / home / share /mnt/ share nfs bg , hard , rw • О О . ...... .. .... ..... ···- ... ·-·. ·-·· .............. --- .............................. - - - -
}1 \l)CI l .i1111, ....................... n.1nux Нужно отметить, что NFS - довольно старое решение, как говорят, класси­ ческое. Существуют различные варианты сетевых и распределенных фай­ ловых систем, например , ClusterNFS, OpenAFS , Parallel Virtual File System (PVFS) и др. Основной недостаток NFS - отсутствие какого-либо шифрования передава­ емых по сети данных. Если вы. используете NFS в защищенной локальной сети, то это, как правило , не проблема (при отсутствии угроз внутри сети). Но когда есть нео9ходимость передавать данные по Интернету, то нужно ис­ пользовать шифрование. Один из способов добавления шифрования к - использование виртуальных частных сетей (VPN), NFS в которых все данные между удаленными системами передаются в зашифрованном виде . В этом случае NFS имеет право на существование в Интернете. Список использованны х источников информации: • Колисниченко Д.Н. «LINUX. Полное руководство по работе и администриро- ванию» • https://ru.wikipedia.org/wiki/Softlanding_Linux_ System • www.kemel.org • https://docs.huihoo.com/doxygen/linux/keme\/3.7/structtask_ struct.html • http: //tldp.org/НOWTO/LVM-HOWTO/ • http://www.iakovlev.org/index.html • https: //miпors.edge.kemel.org/puЬ/linux/libs/pam/ • https ://www.freepik.com/free-vector/minimal-white-background-wi th-3 d-circulardesign_ 8776623 .htm?query=c#from_ view=detail_ also\ike • https://www.insight-it.ru/category/linux/ • http://wiki.opennet.ru/RPM • https ://it-Ыack.ru/linux/3 / • . ....... .... .. .... ..... .. . ... . .... .... ... ---- ----- ... -- . ----·-·····-· ...... -- ··- -···
Матвеев М. Д. Ядро Linux СБОРКА ~ НАСТРОИКА УПРАВЛЕНИЕ Ipynna подготовки издания: Зав . редакцией компьютерной литературы : М. В. Финков Редактор : Е. В. Финков Корректор: А. В. Громова ООО "Издательство Наука и Техника" ОГРН 1217800116247, ИНН 7811763020, КПП 781101001 192029, r. Санкт-Петербург, пр . Обуховской обороны, д. 107, л~т. Б, Подпис а но в печать 13.02.2023. Формат 70х100 1/16. Бумага газетная . Печать офсетная . Объем 22 п .л . Тираж 1500. З аказ 6032. пом . 1-Н Отпечатано с готового оригинал-макета ООО «Принт-М », 142300, М . О ., r. Чехов , ул . Полиграфистов, д.1