Введение в POSIX'ивизм

         

Дисковые накопители


В современных операционках POSIX-семейства поддерживается множество файловых систем. В первом приближении их можно разделить на две группы - реальные, или базирующиеся на дисках (точнее, на блочных устройствах, block based file systems), и виртуальные, под которыми никаких реальных физических устройств не обнаруживается. Есть и промежуточный вид файловых систем - на виртуальных дисках в оперативной памяти (т.н. RAM-дисках). Основным предметом нашего рассмотрения будут файловые системы первой группы - о виртуальных файловых системах я скажу несколько слов под занавес.

Как следует из названия, block based файловые системы размещаются на блочных устройствах, в качестве которых выступают обычно диски и их разделы. И потому рассмотрению ФС этого типа следует предпослать введение о дисковых накопителях.

Дабы не повторять это в дальнейшем, сразу оговорюсь, что почти все сказанное далее относится к дискам с интерфейсом IDE (ATA). SCSI-диски имеют свою специфику, но я с ними дела не имел и собственных впечатлений на сей предмет у меня нет. Да и для пользователя, с ростом объема и скорости ATA-дисков, падением их цены и распространением внешних накопителей с USB- и FireWire-интерфейсами, SCSI становится все менее актуальным. Хотя эту тему и придется затронуть - но не в отношении дисков, а устройств иного типа. Ибо и в Linux, и BSD-системах все не-ATA накопители почему-то любят прикидываться SCSI-устройствами...

Для начала вспомним, что дисковые накопители, как и любые другие устройства, в любой POSIX-совместимой системе предстают перед пользователем в виде файлов специального типа - файлов устройств. Файлы эти расположены в каталоге /dev, и номенклатура их подчиняется правилам, своим для каждого представителя этого семейства ОСей.

В Linux ATA-диски традиционно именовались как /dev/hd?, где hd - общее имя устройств этого класса (рискну предположить, происходящее от hard disk), а символ ? - литера, идентифицирующая конкретный его представитель (табл. 1).

Таблица 1. Номенклатура дисковых накопителей в Linux



Файл Накопитель
/dev/hda Master на 1-м IDE-канале
/dev/hdb Slave на 1-м IDE-канале
/dev/hdc Master на 2-м IDE-канале
/dev/hdd Slave на 2-м IDE-канале
<
Номенклатура устройств - статична, то есть не зависит от физического их наличия: диск, подключенный как Slave ко второй линии встроенного IDE-контроллера, всегда будет именоваться /dev/hdd, даже являясь единственным накопителем в системе (случай чисто гипотетический - трудно представить себе реальные основания для конфигурации такого рода).

Отдельно следует оговорить, что тем же правилам подчиняется именование не только дисков, но и других накопителей с интерфейсом ATA - CD ROM/R/RW, DVD любого вида или отходящих в прошлое внутренних Zip-приводов.

Однако в последнее время большинство "прогрессивных" дистрибутивов используют файловую систему устройств (devfs), вносящую свои коррективы в номенклатуру устройств, в том числе и дисковых.

При использовании devfs для файлов любых ATA-накопителей предназначен каталог /dev/ide (в некоторых дистрибутивах файловая система устройств монтируется в каталог /devices, а каталог /dev сохраняется для совместимости). Файлы накопителей на встроенном основном IDE-контроллере локализуются в подкаталоге /dev/ide/host0 (если используется еще и дополнительный IDE-контроллер, встроенный или внешний, можно увидеть и каталог /dev/ide/host1). А внутри него есть два подкаталога, соответствующие IDE-каналам - /dev/ide/host{/bus0,/bus1}, каждый из которых опять же может делиться надвое - на каталоги target0 и target1, по количеству подключенных устройств. Внутри каталога target0(1) имеется минимум еще один подкаталог lun0. А уж в нем размещаются непосредственно файл дискового устройства - disc.

Таким образом, полное обозначение дискового раздела будет выглядеть как

/dev/ide/host0/bus0/target0/lun0/disc

для первого диска на первом канале основного IDE-контроллера.

Как и в случае старой номенклатуры, правила ее распространяются и на не-дисковые ATA-накопители, в частности, CD. С той только разницей, что именование CD-привода в этой нотации (назовем ее полной) будет выглядеть так:

/dev/ide/host0/bus1/target0/lun0/cd

Предусмотрен и более краткий способ обращения к файлам устройств - через символические (изредка - жесткие) ссылки; назовем этот способ краткой нотацией.


Для файлов дисковых накопителей (независимо от интерфейса - IDE или SCSI) они собраны в каталоге /dev/discs (для файлов CD-приводов, например, - в каталоге /dev/cdrom) с подкаталогами disc0, ... , disc#. И потому к приведенному в качестве примера диску можно обратиться и так:

/dev/discs/disc0/disc

а CD привод будет именоваться следующим образом:

/dev/cdroms/cdrom0

Краткая нотация имеет динамический характер, то есть первый в порядке подключения диск всегда будет представлен устройством /dev/discs/disc0/disc, а второй - /dev/discs/disc1/disc, вне зависимости от того, на каком канале или в каком качестве (Master или Slave) они реально подключены.

Наконец, для совместимости со старыми временами (и старыми привычками) в большинстве дистрибутивов поддерживается и номенклатура обратной совместимости, принятая до внедрения devfs. То есть все тот же дисковый накопитель из примера можно обозвать просто - /dev/hda.

Таким образом, подключение devfs - не препятствие для использования старой номенклатуры накопителей. Правда, это требует соответствующей настройки демона devfsd (точнее, его конфигурационного файла), отвечающего за обратную совместимость. И, при желании, может быть отменено. В частности, такие дистрибутивы, как CRUX и Archlinux, на стадии установки обратной совместимости не используют - при подготовке дисков здесь именовать их приходится только в новой нотации - краткой или полной, без разницы.

При использовании файловой системы devfs имена файлов создаются только для реально существующих в системе устройств (в том числе, для устройств "горячего" подключения, типа PC-карт или USB-драйвов, - и "на лету"). Поэтому, если в системе имеется только единственное IDE-устройство, скажем, жесткий диск как мастер на первом канале, бесполезно было бы искать файлы устройств с именами, отличными от приведенного в примере. Что удобно, но в некоторых реализациях devfs может создавать сложности. Впрочем, как сказал бы Киса Воробьянинов, к теме, которую я в данный момент представляю, это не относится...



В последнее время в большинстве дистрибутивов Linux, вместо файловой системы устройств, активно внедряется механизм udev (о чем будет говориться далее). При этом происходит возврат к старой номенклатуре устройств, в том числе и дисковых накопителей: /dev/hda и так далее. Однако, как и в devfs, файлы создаются только для реально имеющихся в машине устройств.

Несколько отлична номенклатура накопителей во FreeBSD и DragonFlyBSD. Здесь файлы устройств ATA-дисков именуются в общем виде как ad#. Как нетрудно догадаться, аббревиатура ad происходит от ATA Disk, а # - численный идентификатор, соответствующий номеру конкретного накопителя в порядке его подключения к IDE-разъемам (табл. 2)

Таблица 2. Номенклатура дисковых накопителей во FreeBSD и DragonFlyBSD

Файл Накопитель
/dev/ad0 Master на 1-м IDE-канале
/dev/ad1 Slave на 1-м IDE-канале
/dev/ad2 Master на 2-м IDE-канале
/dev/ad3 Slave на 2-м IDE-канале
Во FreeBSD и DragonFlyBSD по умолчанию также принята статичная нумерация файлов дисковых устройств, хотя это можно изменить при перекомпиляции ядра.

В отличие от Linux, во FreeBSD для приводов CD ROM принята своя номенклатура - файлы этих устройств именуются как /dev/acd0, /dev/acd1 и (если такое реально бывает) так далее, вне зависимости от контроллера, к которому они подключены. Имена SCSI-приводов для компакт-дисков - /dev/cd0 и так далее. Самих по себе устройств с таким интерфейсом в пользовательской машине почти наверняка нет. Однако в этом качестве перед системой предстают обычные ATAPI CD- и DVD-приводы, если в ядре включена поддержка эмуляции SCSI (CAM - Common Access Metod). А она требуется для записи DVD, и, в некоторых случаях, также и CD-дисков.

Во FreeBSD 5-й ветки также используется файловая система устройств devfs. Однако влияния на номенклатуру устройств она не оказывает: все низкуровневые утилиты в этой ОС разрабатываются совместно с ядром, и потому задача обратной совместимости тут не ставится. Единственно, что в каталоге /dev установленной FreeBSD 5-й ветки будут присутствовать только файлы реально имеющихся устройств - например, /dev/ad0 и /dev/acd0.


Тогда как в более старых ветвях мы увидели бы также созданные "про запас" файлы /dev/ad0, /dev/ad1 и /dev/ad2, хотя попытка обращения к ним ничего, кроме сообщения об ошибке, и не дала бы.

Наконец, прочие BSD-системы (Net- и OpenBSD) также располагают собственной терминологией в отношении дисковых устройств. Соответствующие им файлы именуются как wd0 и так далее (табл. 3).

Таблица 3. Номенклатура дисковых накопителей в NetBSD и OpenBSD

Файл Накопитель
/dev/wd0 Master на 1-м IDE-канале
/dev/wd1 Slave на 1-м IDE-канале
/dev/wd2 Master на 2-м IDE-канале
/dev/wd3 Slave на 2-м IDE-канале
Причем, в отличие и от Linux, и от FreeBSD, в OpenBSD номенклатура дисков по умолчанию динамична - то есть диски нумеруются по порядку, вне зависимости от линии контроллера и положения на ней (Master или Slave). То есть имена устройств в табл. 3 будут отвечать реальности только при наличии четырех дисков. Хотя, как и во FreeBSD, такой порядок может быть изменен при переконфигурировании ядра.

Жесткие диски - не единственные накопители, которые можно обнаружить в современной машине: все более возрастает роль разного рода сменных носителей, вытеснивших, наконец, из этой ниши аксакала - трехдюймовый дисковод. Накопители такие бывают двух типов - с интерфейсом FireWire и USB. О первых не могу сказать ничего определенного - не только не пользовался, но и даже не видел. А вот USB-драйвы (в просторечии - флэшки) заслуживают нескольких слов.

Потому что это - и есть те устройства из числа распространенных, которые изображают из себя SCSI-диски. И соответствующие им файлы устройств подчиняются правилам, установленным для последних. То есть в Linux по старой (и очень новой - при udev) номенклатуре они будут именоваться как /dev/sda, /dev/sdb и так далее. По новой же в полной нотации - точно как SCSI-диски:

/dev/scsi/host0/bus0/target0/lun0/disc

Впрочем, в краткой нотации USB-привод будет выглядеть обычным винчестером:

/dev/discs/disc1/disc

Во FreeBSD USB-накопители также предстают в качестве SCSI-дисков, и, в соответствие с принятыми здесь правилами, имена соответствующих им файлов устройства будут выглядеть как /dev/da1, /dev/da2 и так далее.

К слову сказать, точно так же, как и флэшки будут обычно выглядеть (и в Linux, и во FreeBSD) и цифровые камеры с USB-интерфейсом, точнее, встроенные в них или съемные носители информации; как, впрочем, и карт-ридеры для чтения последних. Да и именование внешних мобильных винчестеров с USB-интерфейсом (типа Fujitsu HandyDrive) подчиняется тем же правилам.

Теоретически ничто не мешает создавать файловые системы непосредственно на дисковых устройствах. Однако практически так почти никогда не поступают - диски принято делить на разделы (partitions в терминах DOS/Windows и Linux, slices в терминологии FreeBSD). Однако прежде чем говорить о разбиении диска, необходимо сказать


Файловая система BSD-семейства


Для файловой системы BSD-систем, начиная с 4.2BSD, используется общее родовое наименование - FFS (Fast File System). Название это отражает их большее быстродействие относительно первознанной s5fs, хотя среди современных файловых систем они - в числе самых медленных. Реализация UFS для FreeBSD и DragonFlyBSD носит название UFS (Unix File System). Во FreeBSD 5-й ветке используется усовершенствованная, 64-разрядная, разновидность последней - UFS2. Она с некоторых пор поддерживается также в NetBSD и DragonFly, хотя и не является в них используемой по умолчанию. Фактически FFS и разновидности UFS - единственные нативные файловые системы для ОС BSD-семейства, хотя на уровне обмена данными в них можно использовать файловые системы FAT-семейства и, с оговорками, некоторые типы файловых систем Linux.

Как уже говорилось ранее, дисковый раздел, на котором создается файловая системы, - это, говоря метафорически, группа смежных цилиндров, разбитых на физические блоки по 512 байт. Однако специфика файловых систем BSD-клана заключается в том, что при их создании раздел делится еще и на части фиксированного объема (зависящего от объема раздела). Это так называемые группы цилиндров, каждая из которых имеет включает три самостоятельные части:

суперблок, идентичный по содержанию для всех групп;

блок группы цилиндров, оную описывающий; одной из важнейших его частей является индексная таблица (или таблица inodes);

область блоков данных.

Рассмотрение их устройства целесообразно начать с конца списка, то есть с области данных.

Область данных (она занимает подавляющий объем пространства каждой группы цилиндров) образована блоками файловой системы. Подобно физическому блоку, о котором речь была ранее, блок файловой системы (именуемый также блоком логическим) представляет собой квант информации, доступный за одну операцию чтения/записи, но уже не дисковой головки, а операционной системы. Очевидно, что логический блок не может быть меньше блока физического (то есть 512 байт), и размер его обязательно кратен целому числу последних.


Понятие логического блока введено для повышения производительности дисковых операций. Не требует доказательства утверждение, что скорость обмена данными квантами по 1 Кбайт будет выше, чем 512-байтными, 2-килобайтными - еще быстрее, и так далее. И потому с точки зрения быстродействия файловых операций выгоден максимальный размер логического блока файловой системы.

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

Ясно, что размер фрагмента все равно не может быть меньше физического блока. При этом UFS накладывает на него и встречное ограничение - минимальный размер фрагмента определяется в 1/8 логического блока. Другие же возможные значения - 1/4 и 1/2 блока файловой системы (очевидно, что выделение фрагмента в размере блока равносильно отказу от фрагментации блока вообще, хотя это, как будто бы, не запрещено).

Каким образом определяется принадлежность блока данных тому или иному файлу? К помощью индексной таблицы, именуемой также таблицей индексных дескрипторов или таблицей inodes. Она образована некоторым (конечным) количеством записей фиксированной длины (128 байт в UFS, 256 - в UFS2), каждая из которых однозначно соответствует одному файлу, как реально существующему, так и только могущему быть созданным.

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


А поскольку количество этих записей - величина конечная, именно объем индексной таблицы и определяет, сколько файлов реально может быть создано в данной файловой системе. Исчерпание свободных записей в ней приводит к тому, что, вне зависимости от объема свободного дискового пространства, ни одного нового файла создать не удастся.

Таблицы inodes содержатся в блоке группы цилиндров, наряду с картами свободных/занятых inodes и карты свободных/занятых блоков данных). Это имеет целью размещение inodes и относящихся к ним блоков данных максимально близко друг к другу, что, кроме повышения производительности (за счет минимизации перемещений головок), влечет за собой и сведение к минимуму той самой внешней фрагментации данных, о которой, как факторе несущественном, упоминалось выше.

Однако сведений об объеме индексной таблицы в блоке группы цилиндров не обнаруживается. Ибо место их размещения - тот самый суперблок, который идет первым в любом разделе (вообще-то первым будет загрузочный блок, но реально он занят только в загрузочном же разделе - во всех остальных для него просто зарезервировано место). А также дублируется в каждой группе цилиндров - чем обеспечивается устойчивость к механическим повреждениям диска. Кроме этого, в суперблоке же записывается размер блока файловой системы и их суммарное количество, число блоков данных, размер блокового фрагмента и их число в блоке, число блоков, реально занятых файлами, объем партиции, перманентно резервируемый как свободный, и еще множество характеристик файловой системы.

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

Исправлению обоих недостатков служит так называемый механизм SoftUpdates (оставим этот термин без перевода - варианты оного типа "мягких обновлений" не только не блещут литературным изяществом, но и сути дела не проясняют).


Он детально описан в специальной статье Макказика и Ганджера, смысла пересказывать которую я не вижу (благо она имеется в русском переводе - http://www.osp.ru/os/1999/07-08/13.htm). В двух же словах суть этого механизма - в сведении к минимуму синхронных операций записи без явно асинхронного манипулирования метаданными, с одной стороны, но и без предварительного журналирования метаданных (как в файловых системах типа ReiserFS или XFS) - с другой.

Реализуется это за счет так называемых зависимостей обновления. Что такое эти зависимости - интуитивно ясно из примера создания нового (для простоты - пустого) файла. Для этого требуется:

запись в таблице inodes, с заполнением полей типа файла, его идентификатора, счетчика ссылок, ну и прочих там - прав доступа в соответствие с умолчальной маской, и так далее;

изменение карты свободных/занятых inodes в блоке группы цилиндров (соответствующий новому файлу inode должен быть помечен в ней битом занятости);

внесение записи вида "идентификатор - имя_файла" в структуру каталога, в котором новый файл создается, что обеспечивает ту самую единственную ссылку в соответствующем поле inode файла.

С точки зрения целостности файловой системы, эти операции должны быть выполнены именно в указанной последовательности. То есть наличие в каталоге имени файла с идентификатором незаполненного (еще не созданного или уже уничтоженного) inode - явный непорядок: именно для исправления такого рода безобразий и запускается программа проверки диска после аварийного завершения сеанса.

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


Файловые системы Linux


В Linux длительное время также имелась только одна нативная файловая система, носящая имя Ext2fs. О ней написано немало, поэтому буду краток. Название ее расшифровывается как "вторая расширенная файловая система"; "расширенная" она - по сравнению с файловой системой ОС Minix, послужившей прототипом Linux (и до сих пор используемой на отформатированных в этой ОС дискетах), "вторая" - потому что ранние версии Linux базировались на Extfs с более ограниченными возможностями.

По способу организации хранения данных она - типичная представительница файловых систем Unix. Отличительная ее особенность - дробление дискового раздела на группы блоков и наличие нескольких копий суперблока, что повышает надежность хранения данных. Кроме того, для нее характерен очень эффективный механизм кэширования дисковых операций, что обеспечивает замечательное их быстродействие - едва ли не рекордное среди всех известных файловых систем. Оборотная сторона чего, однако, - относительно слабая устойчивость при аварийном завершении работы (вследствие мертвого зависания или отказа питания), поскольку отложенность записи изменений файлов делает весьма высокой вероятность нарушения связи между их inodes и блоками данных.

Конечно, времена, когда некорректный останов Linux-машины грозил полным разрушением файловой системы, остались в далеком прошлом. Однако в любом случае останов системы без штатного размонтирования файловых систем приводит к тому, что в них не устанавливается упоминавшийся ранее неоднократно "бит чистого размонтирования". А без этого утилиты обслуживания диска (такие, как программа проверки fsck) при перезагрузке не воспринимают их как целостные и начинают проверку, которая при современных объемах дисков может занять немалое время.

Проблема нарушения целостности файловой системы при некорректном завершении работы в большей или меньшей мере характерна для всех ОС семейства Unix. И потому с давних пор в них разрабатываются т.н. журналируемые файловые системы.
Журнал -- это нечто вроде log-файла дисковых операций, в котором фиксируются не выполненные, а только предстоящие манипуляции с файлами, вследствие чего оказывается возможным самовосстановление целостности файловой системы после сбоя.

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

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

Текущие версии ядра Linux поддерживают в качестве нативных четыре журналируемые файловые системы: ReiserFS и Ext3fs, специфичные для этой ОС, XFS и JFS - результаты портирования в Linux файловых систем, разработанных первоначально для рабочих станций под ОС Irix (SGI) и AIX (IBM), соответственно. Правда, широкое признание получили только три первых, так что о JFS я говорить не буду.

Файловая система ReiserFS оказалась для Linux исторически первой из журналируемых - она поддерживается каноническим ядром c http://www.kernel.org, начиная с первых версий ветви 2.4.x. И была единственной, разработанной "с нуля" специально для этой ОС Хансом Райзером и его фирмой Namesys(http://www.namesys.com). В ReiserFS осуществляется журналирование только операций над метаданными файлов. Что, при определенном снижении надежности, обеспечивает высокую производительность: на большинстве типичных пользовательских задач она лишь незначительно уступает Ext2fs.


А на такой, достаточно обычной, операции, как копировании большого количества мелких файлов, существенно ее опережает.

Кроме этого, ReiserFS обладает уникальной (и по умолчанию задействованной) возможностью оптимизации дискового пространства, занимаемого мелкими, менее одного блока, файлами (а следует помнить, что в любой Unix-системе такие файлы присутствуют в изобилии): они целиком хранятся в своих inode, без выделения блоков в области данных - вместе с экономией места это способствует и росту производительности, так как и данные, и метаданные (в терминах ReiserFS - stat-data) файла хранятся в непосредственной близости и могут быть считаны одной операцией ввода/вывода.

Вторая особенность ReiserFS - то, что т.н. хвосты файлов, то есть их конечные части, меньшие по размеру, чем один блок, могут быть подвергнуты упаковке. Этот режим (tailing) также включается по умолчанию при создании ReiserFS, обеспечивая около 5% экономии дискового пространства. Что, правда, несколько снижает быстродействие, и потому режим тайлинга можно отменить при монтировании файловой системы. Однако упаковка хвостов автоматически восстанавливается на файловой системе, в которую было инсталлировано новое ядро - что по некоторым причинам требует внимательного отношения.

ReiserFS не совместима с Ext2fs на уровне утилит обслуживания файловой системы. Однако соответствующий инструментарий, объединенный в пакет reiserfsprogs, уже давно включается в штатный комплект современных дистрибутивов (или, в крайнем случае, может быть получен с сайта Namesys.

Более серьезная проблема с совместимостью - в том, что распространенные загрузчики Linux (и Lilo, и GRUB - хотя и по разным причинам) иногда не способны загрузить ядро Linux с раздела ReiserFS, оптимизированного в режиме тайлинга. А поскольку, будучи отключен, этот режим обладает свойством самовосстановления, пользователь может столкнуться с тем, что после пересборки ядра система просто откажется загружаться. Так что ReiserFS не рекомендуется к употреблению на загрузочном разделе.



В отличие от ReiserFS, Ext3fs - не более чем журналируемая надстройка над классической Ext2fs, разработанная Стивеном Твиди в компании Red Hat и поддерживаемая ядром Linux, начиная с версии 2.4.16. Как следствие такого происхождения, она сохраняет со своей прародительницей полную совместимость, в том числе и на уровне утилит обслуживания (начиная с версии 1.21 объединяющего их пакета e2fsprogs). И переход от Ext2fs к Ext3fs может быть осуществлен простым добавлением файла журнала к первой, не только без переформатирования раздела, но даже и без рестарта машины.

Из этого вытекает первое преимущество Ext3fs, особенно весомое в случае большого парка компьютеров. Второе же - чуть ли не максимальная надежность: Ext3fs является единственной системой из рассматриваемых, в которой возможно журналирование операций не только с метаданными, но и с данными файлов. Ибо в Ext3fs предусмотрено три режима работы - полное журналирование (full data journaling), журналирование с обратной записью (writeback), а также задействуемое по умолчанию последовательное журналирование (ordered).

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

В режиме отложенной записи, напротив, в файл журнала записываются только изменения метаданных файлов, подобно всем рассмотренным ниже файловым системам. То есть никакой гарантии сохранности данных он не предоставляет, однако теоретически обеспечивает наибольшее (в рамках Ext3fs) быстродействие.

В последовательном режиме также физически журналируются только метаданные файлов, однако связанные с ними блоки данных логически группируются в единый модуль, называемый транзакцией (transaction).


И эти блоки записываются перед записью на диск новых метаданных, что, хотя и не гарантирует сохранности самих данных, весьма последней способствует. Причем - при меньших накладных расходах по сравнению с полным журналированием, обеспечивая промежуточный уровень быстродействия. Опять же в теории - на практике все может быть не совсем так.

Файловая система XFS, в отличие от молодых ReiserFS и ext3fs, развивается фирмой SGI для ее собственного варианта Unix на протяжении более десятка лет - впервые она появилась в версии Irix 5.3, вышедшей в 1994 г. Но в Linux она была портирована лишь недавно (текущая ее версия свободно доступна с SGI's XFS page - http://oss.sgi.com/projects/xfs), и штатно поддерживается ядром, лишь начиная с его ветки 2.6.X.

XFS - единственная 64-разрядная файловая система из используемых в Linux. Однако уникальность ее - не только в этом. Особенностями XFS являются:

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

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

списки контроля доступа (ACL, Access Control List) и расширенные атрибуты файлов (extended attributes), рассмотрение которых далеко выходит за рамки нынешней темы.

В результате XFS предстает как очень сбаллансированная файловая система, ориентированная на размещение в очень больших дисковых разделах для рабботы с очень большими файлами.

И, наконец, эпоним журналируемых файловых систем, JFS (разработка IBM для собственной версии Unix, AIX), уже долгое время поддерживается ядром Linux в качестве нативной.


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

На уровне обмена данными и Linux, и BSD поддерживают множество файловых систем, некоторые - только в режиме чтения, другие же - и записи тоже. Важнейшими для пользователя являются файловые системы CD- и DVD-дисков (ISO9660 и UDF, соответственно) и вариации на тему FAT, а также NTFS (последняя - практически только в режиме чтения).

Кроме того, Linux и BSD теоретически поддерживают файловые системы друг друга. Теоретически - потому, что прочитать из Linux раздел с UFS - задача нетривиальная (а раздел с UFS2 - пока невозможная), запись же на него, как пишут в документации, - дело рискованное для сохранности данных. Во FreeBSD и DragonFlyBSD же поддерживается чтение и запись для файловых систем Ext2fs и Ext3fs без особых сложностей (по крайней мере, я с проблемами здесь не сталкивался). Ведутся работы по восприятию ReiserFS и XFS (пока - только в режиме чтения), существуют и патчи для доступа к JFS.

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


Физика файловых систем


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



Немного о "геометрии"


Слово "геометрия" в заголовке рубрики взято в кавычки не случайно. Дело в том, что с тех пор, как объем дисков перевалил за 500 с небольшим мегабайт (ограничение старых BIOS персональных, ранее именовавшихся IBM-совместимыми, компьютеров), с реальной их геометрией пользователь никогда не сталкивается. Софт, прошитый в дисковой электронике (т.н. firmware) преобразует ее к виду, доступному восприятию BIOS - на деталях, как именно это делается, останавливаться не буду.

А доступная BIOS геометрия диска описывается в терминах цилиндр/головка/сектор (cylinders/heads/sectors, C/H/S). Фигурально говоря (а, повторяю, все, относящееся к дисковой геометрии, ныне следует понимать исключительно фигурально, аллегорически или метафорически), головки считывают информацию с концентрических магнитных дорожек (tracks), на которые поделена каждая дисковая пластина. Вертикальная совокупность треков с одинаковыми номерами на всех пластинах, составляющих диск как физическое устройство, и образует цилиндр. А сектора нарезают пластину, вместе с ее треками, на радиальные фрагменты, именуемые блоками. То есть это можно представить себе таким образом, что блок лежит на пересечении (в пространстве) цилиндра, трека и сектора.

Число треков и секторов в современных дисках обычно фиксировано (вернее, предстает таковым в BIOS): 255 треков нарезается на 63 сектора каждый, что в совокупности дает 16065 блоков на цилиндр. А количество цилиндров определяется объемом диска (в арифметические вычисления вдаваться не буду). Важно здесь только то, что головки диска механически двигаются синхронно по поверхности всех пластин. То есть если на одной пластине информация считывается с 1-го трека, то и все прочие головки перемещаются на ту же дорожку - каждая на своей пластине.

Повторяю, все это условно - хотя бы потому, что понятие цилиндра в геометрическом смысле слова очень трудно применить к современным дискам, часто не то что однопластинным, а даже, если так можно выразиться, полупластинным (то есть только с одной задействованной стороной единственной пластины).
Но разбираться с этой геометрией - дело firmware и BIOS, для нас же интересны именно цилиндры - совокупность треков, к которым осуществляется синхронный доступ, и блоки - минимальные кванты дискового пространства.

Образующие цилиндры треки создаются при первичной заводской разметке диска - т.н. низкоуровневом форматировании. Из сказанного выше очевидно, что доступ к данным в пределах одного цилиндра или группы соседних будет выполнен быстрее, чем к данным, записанным частично на первый и, скажем, на последний цилиндр диска. Этот случай не столь уж невероятен, как может показаться: в DOS'е, где пространство, занятое стертыми файлами, помечается как неиспользуемое, но реально перезаписывается только тогда, когда по настоящему свободное место на диске вообще исчерпано, подобная ситуация вполне могла бы возникнуть.

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

Где кончается один раздел и начинается другой? Резонные люди из Одессы сказали бы, что полиция кончается именно там, где начинается Беня Крик. Однако для нас очевидно, что для каждого из разделов следует хранить сведения о его начале и конце (то есть номера первого и последнего из задействованных в нем цилиндров). Где их хранить? Для ответа на этот вопрос следует обратиться к понятию блока.

Как и треки, дисковые блоки (или физические - есть еще блоки логические, но это относится уже к файловым системам, о которых речь пойдет в следующем параграфе) создаются при низкоуровневом форматировании, и пользователь влиять на них не может. Размер их также всегда одинаков и равен 512 байтам. Вернее, таким он видится BIOS'у персоналки - каков он на самом деле, одному Аллаху ведомо.

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


То есть мелкие текстовые файлики размером в пару символов (сиречь байт) все равно захватят под себя аж 512 байт, не меньше. С другой стороны, считывание данных блоками по 512 байт будет происходить быстрее, чем если бы при каждом обращении головки к диску данные считывались бы побайтно. Однако и это относится уже к теме файловых систем.

Пока же нас интересен один-единственный блок, образованный первым сектором на первом треке первого цилиндра. Он резервируется под служебную область диска, именуемую главной загрузочной записью (MBR - Master Boot Recodr), которая и считывается BIOS'ом при старте машины. Очевидно, что по прямому назначению MBR используется только в том случае, если диск определен в Setup'е BIOS'а как загрузочный (или просто является единственным в системе). Однако поскольку использование каждого конкретного диска остается на усмотрение пользователя, место под него отводится всегда.

Внутри нулевого блока, помимо прочего (в частности, кода какого-либо начального загрузчика, который может быть туда записан) есть еще один зарезервированный участок. Он предназначен для BIOS'овской таблицы разделов (Partition Table), под которую испокон веков (со времен самой первой IBM PC, кажется) отведено 64 байта. В эту таблицу записываются (или могут быть записаны) данные о разделе (разделах) в определенном, доступном пониманию BIOS'а, формате.

А формат этот предусматривает указание для каждого раздела его стартового блока, размера в байтах, идентификатора типа файловой системы (это, вопреки названию, совсем не то же самое, что файловая система, о которой речь пойдет в одном из последующих параграфов) и (только для одного из разделов) флага активности (то есть помечающего данный раздел как загрузочный). Последнее необходимо для некоторых операционок типа DOS, хотя и Linux'у, и любой BSD-системе флаг этот глубоко безразличен.

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


Эти разделы называются первичными или, не совсем точно, физическими. Так как в большинстве случаев такие разделы могут быть также поделены на части - разделы логические (о чем речь впереди).

Повторю еще раз - это относится только к машинам с PC BIOS, то есть обычным персоналкам. На всякого рода PowerPC, Sparc'ах и тому подобных станциях все может быть совсем по другому.

Как можно заметить, в описание раздела входит идентификатор файловой системы. Это - некоторое число (в BSD обычно в десятичном представлении, в Linux'е, например, - в шестнадцатеричном), которое ставится в соответствие с файловой системой операционки, планируемой к размещению на диске. Так, раздел, предназначенный для FreeBSD (и DragonFlyBSD - тип его 4.2BSD), имеет идентификатор 165 (десятичный) или A5 (шестнадцатеричный), раздел для Linux (Linux native) - 131 или 83, соответственно, FAT16 - 6, расширенный раздел (т.н. DOS Extended) - 5, и так далее. В таблице 4 приведены значения наиболее важных для пользователя Linux и BSD-систем идентификаторов типов разделов (по выводу Linux'ового fdisk, то есть в шестнадцатеричном исчислении) с их краткой характеристикой.

Таблица 4. Значения идентификаторов типов разделов

Значение, hex Название Характеристика
1 FAT12 Файловая система DOS-дискет
4 FAT16

Файловая система старых (ниже 4-й) версий DOS
5 Extended Расширенный раздел DOS
6 FAT16 Обычный раздел DOS (до 2 Гбайт)
b W95 FAT32 Раздел Windows 95 (от OSR2 и выше)
63 GNU HURD Раздел ОС HURD
81 Minix Раздел ОС Minix, используется на дискетах Linux
82 Linux swap Раздел подкачки Linux
83 Linux Родной (native) раздел Linux
8e Linux LVM Раздел для использования менеджером логических томов
a5 FreeBSD Раздел FreeBSD и DragonFlyBSD (4.2BSD)
a6 OpenBSD Раздел OpenBSD
a8 Darwin UFS Раздел MacOS X
a9 NetBSD Раздел NetBSD
fd Linux raid auto Раздел для использования в программных RAID
Для использования в Linux непосредственно предназначены, кроме Linux native и Linux swap, так же разделы типа Minix (хотя с отмиранием дискет актуальность его теряется), Linux LVM и Linux raid auto.Кроме того, без всяких дополнительных ухищрений возможен доступ из Linux к разделам FAT любого рода. Прочие из перечисленных типов предназначены для одноименных ОС.

Присвоение разделу какого-либо идентификатора не значит, что тем самым на нем волшебным образом возникает соответствующая файловая система. Нет, он используется только программами дисковой разметки, и просто предопределяет, какого рода вторичная таблица разделов (Disk Label) может быть на нем записана. Но тут мы переходим к разговору


Общие черты файловых систем POSIX-семейства


Итак, файловые системы обычно размещаются на отдельных дисковых разделах или их объединениях. Соотношение между файловыми системами не вполне однозначно. На одном разделе может быть размещена одна файловая система. Однако последняя, в общем случае, может располагаться более чем на одном разделе. Такие технологии, как LVM (Logical Volumes Managers) или программный RAID, позволяют объединить несколько дисковых разделов в единое логическое устройство, которое целиком занимается одной файловой системой. Впрочем, после такого объединения (конкатенации) прежде самостоятельные разделы видятся системой точно так же, как и обычные разделы или слайсы диска.

Физически все файловые системы в ОС, соответствующих стандарту POSIX, организованы сходным образом. И в основе их лежит разделение на три пространственно разобщенные области - суперблок, область метаданных и блоки данных.

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

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

Адреса блоков данных файла, то есть собственно физического расположения его контента на диске, также описываются в таблице inodes. Ну а сами блоки данных, как легко догадаться, и составляют наполнение одноименной области.

Описанным способом была организована первая файловая система первозданного Unix, получившая позднее название s5fs (то есть файловая система System V).
Как уже говорилось в историческом обзоре (см. ), в самой ее приоде были заложены существенные ограничения, не способствовавшие ни надежности, ни быстродействию, ни эффективности использования дискового пространства. И потому разработчики всех более поздних файловых систем POSIX-совместимых ОС, приняв за основу организацию s5fs, вносили в нее те или иные усовершенствования, направленные на исправление указанных недостатков.

Борьба за повышение быстродействия файловых операций осуществлялась дроблением файловой системы на более или менее независимые части, получившие название групп цилиндров (в ОС BSD-семейства), групп блоков (в файловой системе Linux), вплоть до обособления allocation groups в файловой системе XFS, где они представляют фактически самостоятельные файловые подсистемы. В результате этого появилась возможность размещения логически связанной информации в физически смежных областях диска, что минимизировало перемещение дисковых головок, способствуя тем самым скорости доступа к данным.

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

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

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


Однако оно очень важно с точки зрения восприятия файловых операций пользователем, и потому здесь уместно сказать о нем несколько слов.

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

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

Как уже было отмечено, режим кэширования определяется при монтировании файловых систем (как - об этом пойдет речь в ). И в принципе любая из файловых систем Linux или BSD может быть смонтирована как в том, так и в другом режиме. Однако файловые системы BSD традиционно используются в частично синхронном режиме, а все файловые системы, поддерживаемые в Linux - в асинхронном.

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

В BSD-системах в качестве метода борьбы с этими явлениями была разработка матода SoftUpdates (о котором будет сказано чуть ниже). В Linux'е же основным направлением в повышении надежности файловых операций явилось развитие так называемых журналируемых файловых систем.Журнал -- это часть файловой системы, отведенная под протоколирование выполненных и предстоящих файловых операций, а также под сохранение данных о текущем (на некие моменты времени) ее состоянии. Что, в случае аварийного завершения работы, нарушившего целостность данных и (в первую очередь) метаданных, дает возможность откатиться назад, в последнее "нормальное" состояние.


Основные типы файловых систем POSIX-мира


Таковы общие особенности файловых систем Unix и его производных. Теперь охарактеризуем наиболее используемые в свободных ОС POSIX-семейства их разновидности.



Особенности BSD-разметки


Совершенно иначе (как по существу, так и с точки зрения именования файлов устройств) выглядит BSD-стиль разметки (BSD Label), используемый во FreeBSD, Net- и OpenBSD. Здесь также может быть использована BIOS-таблица, заполнение которой создаст четыре первичных раздела. В терминологии FreeBSD они именуются слайсами (slices - наиболее точным переводом будет "отрезки"), чтобы отличать их от партиций (partitions) BSD-разметки. Слайсы в номенклатуре файлов устройств маркируются добавлением к имени файла диска литеры s и порядкового номера (в отличие от дисков, начиная с единицы), что для Master'а на 1-м IDE-канале будет выглядеть так (табл. 6).

Таблица 6. Номенклатура BSD-слайсов

/dev/ad0s1 1-й слайс
/dev/ad0s1 2-й слайс
/dev/ad0s1 3-й слайс
/dev/ad0s1 4-й слайс

Если одному или нескольким из слайсов будет присвоен идентификатор BSD-системы - 165 в десятичном исчислении (как уже говорилось, он называется 4.2BSD), то в его начальный блок запишется собственно BSD-таблица разделов (BSD Label). В соответствие с ее форматом, каждый слайс с ID 165 абсолютно равноправен и может быть поделен на логические разделы (собственно partitions, в терминологии FreeBSD, именуемые в остальных BSD-системах подразделами - subpartitions).

Для партиций в BSD-таблице предусмотрено восемь (FreeBSD) или шестнадцать (DragonFlyBSD) записей. Соответствующие им разделы номенклатурно маркируются добавлением к имени файла слайса литеры - от a до h (или - до p в случае с DragonFly). То есть таких логических разделов, казалось бы, может быть создано 8 (или, соответственно, 16). Однако практически это не совсем так (вернее, совсем не так).

Начать с того, что одна из записей (третья по счету, маркируемая литерой c) резервируется для описания всего слайса в целом - например, ad0s1c, необходимость чего станет ясной в дальнейшем. Далее, первая запись таблицы, соответствующий которому файл устройства маркируется как ad#s#a, отводится для описания корневого раздела файловой системы.
А очевидно, что на конкретной локальной машине корневой раздел может быть только один, вне зависимости от количества дисковых разделов и даже физических дисков.

Наконец, вторая запись (файл устройства - ad#s#b) предназначена исключительно для описания раздела подкачки (swap-раздела), который, во-первых, не может содержать данные, и во-вторых, является единственным на весь диск (ясно, что создавать по своп-разделу в каждом слайсе бессмысленно, хотя при наличии двух физических дисков поделить между ними пространство подкачки - идея вполне здоровая). В итоге на четырех слайсах физического диска средствами FreeBSD может быть создано 22 раздела - 1 корневой, один раздел подкачки и 20 разделов для хранения данных. Максимальное же количество разделов в случае с DragonFlyBSD предлагается подсчитать заинтересованным лицам.

Практически, однако, так никто, насколько я знаю, не делает. Создание слайсов преследует своей целью разместить на диске более чем одну операционку и сохранить возможность обмена данными между ними (теоретически к BSD-разделам можно обращаться из Linux'а, если пересобрать его ядро должным образом; хотя обратная процедура - обращение к Linux-разделу из BSD-системы, - гораздо проще).

Если же весь наличествующий диск планируется отдать на растерзание какой-либо BSD-системе, то проще создать один-единственный слайс на (почти) весь его объем, оставив записи в BIOS-таблице для остальных неиспользованными. Ну а семи (и, тем более, 15) позиций BSD-таблицы обычно достаточно для обособления всех необходимых ветвей файловой системы, таких, как /usr, /tmp, /var и /home. Впрочем, в ряде случаев целесообразно и разнесение разделов по двум слайсам, но - не более.

Разметка диска, использующая записи в BIOS-таблице первого блока, называется разметкой в режиме совместимости. Вне зависимости от того, создается ли один слайс для BSD-системы или несколько отдельных - для каждой операционки, в режиме совместимости в начале диска резервируется пространство в размере 63 блоков (всего около 30 Кбайт), в котором не только сохраняется в неприкосновенности "умолчальный" MBR, но и остается место для записи кода какого-либо стороннего загрузчика.


В итоге диск остается доступным для других операционных систем, по крайней мере теоретически.

Однако использование режима совместимости и BIOS-таблицы разделов во FreeBSD не является обязательным. Вполне допустимо записать в MBR, вместо таблицы BIOS, непосредственно BSD-таблицу разделов. В этом случае понятно, что слайсов как таковых не создается, а все дисковое пространство представляет собой как бы единый слайс, и может быть разбито на BSD-партиции по тем же правилам, что и отдельный слайс. И тут становится ясной необходимость резервирования третьего поля BSD-таблицы - именно в ней и описывается весь наш диск, целиком отведенный под BSD-систему.

Такое обращение с диском именуется режимом эксклюзивного использования, или Dangerously Dedicated. Вопреки названию, в нем не таится никакой опасности ни для данных пользователя, ни для его здоровья. А единственная подстерегающая его опасность - это то, что диск в эксклюзивном режиме не будет опознан никакой другой операционной системой, установленной на данном компьютере (обращению к диску по сети он препятствий не составит). Однако это - чисто теоретическое неудобство, потому что ни одна из известных мне операционок все равно не умеет толком работать с BSD-разделами и файловой системой FreeBSD (особенно современной - UFS2). А, скажем, при наличии на другом физическом диске мультизагрузчика GRUB, FreeBSD с "эксклюзивного" диска вполне может быть им загружена.

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

Тем не менее, в документах проекта FreeBSD всегда подчеркивается, что эксклюзивный режим - в частности, из-за грошовой экономии дискового пространства, - следует использовать лишь в исключительных случаях.Один из резонов к такому использованию - несоответствие "геометрии" диска, видимой из BIOS, и того представления о ней, которое складывается у FreeBSD (подробнее на эту тему можно прочитать в официальном FreeBSD FAQ - http://www.freebsd.org.ua/doc/ru_RU.KOI8-R/books/faq/index.html).

Схема разметки диска в BSD-стиле принята и в других ОС этого семейства, с той разницей, что термин слайс ни в OpenBSD, ни в NetBSD не применяется, и имена файлов разделов именуются - /dev/wd0a, /dev/wd0b и так далее. А в NetBSD, кроме литеры c, предназначенной для описания всего диска, резервируется еще и литера d - файл устройства /dev/wd0d также предназначается для описания первичного раздела целиком.

В ОС BSD-семейства может быть иным и формат таблицы разделов слайса. В частности, в DragonFlyBSD он позволяет разделить слайс не на 8, как во FreeBSD, а на 16 логических разделов.


RAID и LVM


Дисковые разделы любого рода создаются в целях не только размежевания, но и объединения, в результате которого части различных физических носителей предстают перед системой в качестве непрерывного дискового пространства, на котором может быть создана единая файловая система. И целям объединения служат разнообразные технологии программных RAID и LVM.

Понятие RAID родилось из потребности представить набор дисков в виде единого дискового пространства, и первоначально было реализовано посредством специализированных контроллеров с интерфейсами SCSI или ATA (ныне также и Serial ATA). Это - так называемые физические RAID. Конечно, в них за объединение дисков отвечают соответствующие программы, однако они прошиты в микросхемах контроллера, расположенного либо на отдельной карте расширения, либо, как это стало обычным в последнее время, встроенного в материнскую плату.

Объединение дисков и их разделов возможно и при отсутствии специфического "железа" - именно такая реализация называется программным RAID (Soft RAID). Оно требует а) поддержки ядро операционной системы, и б) наличия соответствующего программного инструментария.

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

К массивам без избыточности относятся т.н. линейный режим (linear RAID) и RAID level 0. Первый - это просто последовательное объединение двух и более дисков, так, что они видятся системой как единое устройство. И запись на них осуществляется последовательно - сначала на первый диск, по заполнении его - на второй, и так далее. Диски или разделы, объединяемые в линейный RAID, могут быть произвольного объема, на их количество также не накладывается никаких ограничений.

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

Массивы нулевого уровня называются также RAID со strip-режимом - это попарное объединение дисков с распараллеливанием операций чтения/записи). В них каждая порция записываемых данных расслаивается на два равных по размеру логических блока (chunks - этот термин лучше оставить без перевода), один из которых в одну и ту же единицу времени записывается на первый диск или раздел массива, другая - на второй. Что теоретически должно способствовать быстродействию дисковых операций. И - способствует практически, но только при условии, что диски массива разнесены на разные IDE-каналы (о SCSI-дисках у нас тоже речи не будет). В противном случае выигрыша в производительности не только не будет, но весьма вероятно даже ее падение.

Очевидно, что в массив нулевого уровня можно объединить только четное количество дисков или разделов. Кроме того, желательно, чтобы они имели примерно одинаковый объем: в противном случае суммарный объем массива будет кратен размеру самого маленького диска, а все избыточное пространство окажется неиспользуемым.

Использование массивов нулевого уровня не способствует надежности хранения данных - при отказе хотя бы одного диска пропадут они все (тогда как в линейном режиме информация на исправном диске в первом приближении сохранится). Тем не менее, применение параллельного режима может быть оправданным: все же приятно, когда пара-тройка гигабайт копируется пусть не вдвое, но хотя бы в полтора раза быстрее.

Массивы с избыточностью призваны в первую очередь повышать надежность хранения данных. А если при этом еще и возрастает быстродействие дисковых операций - это можно рассматривать как бесплатный бонус. На практике в Linux и BSD используются два уровня избыточных RAID'ов - 1-й и 5-й.

RAID level 1 (называемый также режимом зеркалирования, mirroring) - это простое дублирование записываемых данных на двух дисках или разделах, то есть такой массив обладает 100-процентной избыточностью: при выходе из строя одного диска вся информация сохраняется на диске-дублере (хотя в процессе работы они выступают как равноправные).


Очевидно, что, как и в случае с RAID level 0, число дисков или разделов должно быть четным, а их объем - примерно одинаков.

Разумеется, ни о каком росте производительности в массивах первого уровня речи идти не может. Однако на сей предмет level 1 можно комбинировать с level 0 (это называют level 0+1 или, иногда, level 10), когда одна пара дисков в параллельном режиме зеркалируются второй парой. Правда, как нетрудно подсчитать, для этого желательно иметь не только четыре диска, но и соответствующее число отдельных IDE-контроллеров, иначе роста производительности ожидать не придется.

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

Создание и использование программных RAID несколько различается в Linux и BSD-системах. И в обоих случаях требуют некоторых не вполне тривиальных действий, которые будут описаны в . В любом случае после создания массива с ними следует обращаться как с обычными дисковыми разделами - создавать на них файловые системы и монтировать их. Впрочем, и об этом разговор будет в .

Программный RAID-массив - некоторым образом лобовой подход к проблеме объединения дисков. Попробуем подойти к ней с другого бока, благо это допускает в виде технологии логических томов (LVM); правда, доступна она только в Linux.

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


Однако физически ввинтить винчестер в корпус машины - это полдела, нужно еще и сделать его для системы доступным. Как? Возможны варианты.

Можно создать на диске физический раздел, на нем - новую файловую систему и смонтировать ее к файловой системе корневой в заранее созданный каталог, например, $HOME/newhome. Это проще всего, но не всегда - лучше всего. Ведь в итоге единый пользовательский каталог будет состоять из двух физически различных файловых систем, что накладывает некоторые ограничения на манипулирование данными (например, невозможно создать жесткие ссылки на наборы данных другой файловой системы).

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

Второй пример, не менее жизненный. Послушавшись совета резонных людей, мы делим диск на многочисленные разделы, как это будет описано в следующей главе, для всех возможных файловых систем - под каталоги /usr, /usr/local, /opt, /var, /tmp, /home. И очень быстро убеждаемся, что под /usr/local отвели слишком много места - весь нужный нам софт по умолчанию желает собираться в каталоге /opt (с объемом которого мы явно пожадничали). А каталог /usr, вследствие изобилия Иксовых приложений, напротив, заполняется через чур уж стремительно, что отнюдь не есть хорошо: производительность дисковых операций в любом Unix'е стремительно падает по достижении определенного предела заполненности файловой системы. Ну а каталог /tmp просто бездействует - роль хранителя временных файлов, как оказалось, с успехом исполняет файловая система в оперативной памяти - tmpfs. И что, спрашивается, делать? Вариант тотальной архивации и переразбиения дисков - просьба не предлагать.

Обеих ситуаций можно избежать, если предугадать такие коллизии заранее. И еще на стадии разбиения диска прибегнуть к технологии LVM (Logical Volume Manager), то есть управления логическими томами.



Вводное замечание, касаемое терминологии. Пользователи DOS/Windows знают, что логическими томами (logical volumes) называются те части, на которые бьется расширенный (extended) раздел DOS. Однако в случае LVM в понятие логического тома вкладывается, как станет ясно очень скоро, совершенно иной смысл. И потому в этой книге я по возможности именую части расширенного DOS-раздела незамысловато - логическими разделами (впрочем, примерно такая терминология принята в Linux-программах разбиения диска), а звание логического тома сохраняется только за элементом структуры LVM.

Теперь можно перейти к сути дела. Основа технологии LVM - в выделении двух уровней организации дискового пространства, физического и логического. Единица физической организации - физический том (Physical Volume). Это - не что иное, как самый обычный дисковый раздел с определенным идентификатором типа файловой системы - 8e (Linux LVM), который присваивается разделу при его создании, например, программой fdisk. Физический том делится на физические же блоки (physical extents) - кванты дискового пространства, на которые может изменяться размер логических ресурсов (своего рода аналог обычного физического блока винчестера).

Единицей организации логической в LVM выступает группа томов (Volume Group). Она сливает воедино физические тома так, что для ОС они выглядят как единый носитель, и, следовательно, может представляться как нечто вроде логического аналога винчестера. Как и винчестер, группа томов может делиться на разделы (или, напротив, представлять собой единый раздел). Один такой раздел и есть логический том, на котором создаются обычные файловые системы и к которому непосредственно обращается пользователь, например, при монтировании. Он образован последовательностью логических блоков (logical extents), которые можно сопоставить с логическими блоками обычного раздела, размечаемыми при создании файловой системы. А уж эти логические extent'ы (во избежание путаницы оставляю этот термин без перевода) по определенным правилам связываются с extent'ами физическими.



В LVM- HOWTO взаимосвязь элементов LVM иллюстрируется следующим образом:

hda1 hdc1 (PV:s on partitions or whole disks) / / diskvg (VG) / | / | usrlv rootlv varlv (LV:s) | | | ext2 reiserfs xfs (filesystems)

Взаимосвязь физических и логических extent'ов обозначается термином mapping. Причем возможны два варианта такой взаимосвязи - линейный (linear mapping) и "чередующийся" (striped mapping). В первом случае непрерывной последовательности физических extent'ов просто ставится в соответствие столь же непрерывная последовательность extent'ов логических. Во втором же - непрерывная последовательность логических extent'ов соотнесена с физическими extent'ами, чередующимися между физическими носителями: .+-- Volume Group --------------------------------+ | | | +----------------------------------------+ | | PV | PE | PE | PE | PE | PE | PE | PE | PE | | | +----------------------------------------+ | | . . . . | | . . . . | | +----------------------------------------+ | | LV | LE | LE | LE | LE | LE | LE | LE | LE | | | +----------------------------------------+ | | . . . . | | . . . . | | +----------------------------------------+ | | PV | PE | PE | PE | PE | PE | PE | PE | PE | | | +----------------------------------------+ | | | +------------------------------------------------+

Эта схема подобна той, что осуществляется в описанных выше программных RAID-массивах нулевого (strip) уровня и преследует ту же цель - повышение производительности дисковых операций. Правда, последнее достижимо только в том случае, если физические тома, на которых созданы чередующиеся физические extent'ы, расположены не просто на разных дисках, но и на разных IDE-каналах; иначе, напротив, потери производительности могут быть просто катастрофическими.

Из сказанного ясно, что технология LVM наиболее эффективна ( и эффектна) в случае, если в машине имеется более одного физического диска. Однако и в однодисковой системе ее можно использовать с большим успехов (в том числе и в расчете на обогащение вторым накопителем).

Создание логических томов требует поддержки ядром Linux и применения некоторого специфического инструментария, описанного в .


Собственно о разделах


Итак, следствием установлено, что на одном физическом диске может быть создано до 4 (включительно) разделов, каждый их которых может быть приписан к отдельной операционной системе. А что дальше? А дальше следует изучить вопрос стилей разметки разделов.

Стили разметки разделов именуются Disk Label, что не следует путать с метками дисков (disk label) - произвольными именами, которые в DOS (и не только) можно присвоить дисковому разделу. Стиль же разметки - это формат вторичной таблицы разделов, записываемой в первый блок раздела первичного. Эта таблица и определяет характер доступных действий над данным первичным разделом.

Пользователи Windows обычно не имеют причин задумываться над проблемой стилей разметки. Однако стилей таких существует немало - чтобы убедиться в этом, достаточно зайти в меню конфигурации ядра Linux, в подраздел Partition Types раздела File systems. Однако я опять забегаю вперед - нынче из всего этого изобилия нас будут интересовать только два стиля разметки - DOS и BSD.

В DOS/Windows используется (как ни удивительно) DOS-стиль разметки разделов. Он основывается на BIOS-таблице, задействованной лишь частично. А именно - из четырех доступных записей Partitions Table заполняются только две (вернее, только два раздела можно создать средствами стандартного FDISK из DOS/Windows 96/98/ME; как обстоит дело в NT/2000/XP - просто не знаю).

В записи для первого раздела можно указать идентификатор типа файловой системы (например, FAT16 или FAT32), второму же разделу автоматически присваивается идентификатор типа Extended DOS. А уж Extended-раздел может быть далее поделен на логические разделы (Logical Partitions). В терминологии DOS/Windows они именуются логическими томами (Logical Volume). Однако мы зарезервируем этот термин для системы LVM (Logical Volumes Manager), разговор о которой пойдет в одной из ближайших интермедий.

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

В Linux также используется DOS-стиль разметки. Только тут уж BIOS-таблица задействуется по полной программе - стандартными средствами этой ОС (Linux'овым fdisk, имеющим весьма мало общего со своим тезкой из DOS/Windows, его front-end'ом (оболочкой) cfdisk или (почти) универсальной программой parted можно создать все четыре первичных раздела и пользовать их в свое удовольствие. Правда, опять же лишь одному из них можно присвоить идентификатор раздела расширенного и, соответственно, поделить на логические разделы.

Разделы в Linux представляются перед системой (и пользователем) в качестве таких же файлов блочных устройств, как и диски. И номенклатура их подчиняется тем же правилам. В старой (до-devfs'ной) нотации к обозначению целого диска (например, /dev/hda) просто добавляется численный идентификатор раздела (его порядковый номер, начиная с единицы. Идентификаторы с 1-го по 4-й зарезервированы за первичными разделами. Если один из них определен как расширенный, то логические разделы внутри него нумеруются, начиная с 5-го (даже если первичных разделов на диске нет и в помине). То есть типичная картина разбиения диска под Linux будет выглядеть примерно так (табл. 5).

Таблица 5. Примерная схема дисковой разметки в Linux

Файл Раздел
/dev/hda1 1-й первичный раздел
/dev/hda2 2-й первичный раздел
/dev/hda3 3-й первичный раздел, определенный как расширенный
/dev/hda5 1-й логический раздел внутри расширенного
/dev/hda6 2-й логический раздел внутри расширенного
При использовании devfs файлы устройств, соответствующих дисковым разделам, именуются part#, где # - порядковый номер (с 1-го по 4-й - для первичных разделов, с 5-го и далее - для расширенных).


То есть в полной нотации это будет выглядеть так:

/dev/ide/host0/bus0/target0/lun0/part1 /dev/ide/host0/bus0/target0/lun0/part2 /dev/ide/host0/bus0/target0/lun0/part3 /dev/ide/host0/bus0/target0/lun0/part5 /dev/ide/host0/bus0/target0/lun0/part6 ...

а в краткой - таким образом:

/dev/discs/disc0/part1 /dev/discs/disc0/part2 /dev/discs/disc0/part3 /dev/discs/disc0/part5 /dev/discs/disc0/part6 ...

В обоих случаях обращаем внимание на "правильное" написание слова disc... именно так, через букву c.

Интересен вопрос о разделах USB-накопителей (и встроенных носителей цифровых камер). Они поставляются в фабрично отформатированном под vfat виде, однако эта файловая система накладывается на самые разные схемы разбиения. Мне, в частности, приходилось видеть, что форматированию подвергалось все устройство, без разделов (в этом случае обращаться к флэшке из под Linux'а следует - /dev/sda). В иных же случаях файловая система создавалась на 1-м или 4-м первичных разделах - файлы устройств при этом именуются как /dev/sda1 или /dev/sda4, соответственно.

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


Виртуальные файловые системы


До сих пор речь шла о файловых системах, размещаемых на блочных устройствах (block devices based) или, иначе говоря, "реальных". Однако POSIX-совместимые операционки поддерживают еще и несколько типов виртуальных файловых систем. Они не занимают места на диске (или - почти не занимают), располагаясь в оперативной памяти, и служат для специальных целей.

Исторически первой из таких виртуальных файловых систем была файловая система процессов - procfs. Как можно догадаться из названия, она представляет протекающие в системе процессы в виде файлов каталога /proc, откуда и получают информацию о процессах команды типа ps и top. Однако и пользователь может извлечь оттуда немало полезной для себя информации.

В каталоге /proc каждому процессу соответствует подкаталог, именем которого является идентификатор процесса (просто номер в порядке запуска). Внутри такого подкаталога обнаруживается набор файлов (разный, в зависимости от ОС). Содержимое некоторых из них можно посмотреть обычным способом и обнаружить там информацию об имени запустившей процесс команды, используемых ею адресах памяти и так далее.

Множество важной информации содержится в файлах корня /proc. Из них обычными командами просмотра можно извлечь сведения о процессоре (/proc/cpuinfo), текущей конфигурации ядра системы (/proc/config.gz), загруженных его модулях (/proc/modules), устройстах, подсоединенных к шине PCI (/proc/pci) - в частности, иногда только тут можно узнать подробности о своей сетевой карте и внутреннем модеме, необходимые для правильной их настройки.

Следующей виртуальной файловой системой является файловая система устройств - devfs. Она по умолчанию задействована во FreeBSD 5-й ветки и во многих (хотя и далеко не всех) современных дистрибутивах Linux. Чтобы понять ее назначение, нужно вспомнить, как происходило обращение с файлами устройств ранее.

А происходило оно так. Некий набор файлов устройств генерировался при начальной установке системы. Каждый файл устройства характеризовался своим старшим (major) и младшим (minor) номерами.
Первый определял класс устройств, например, диски, терминалы и псевдотерминалы, параллельные или последовательные порты, и так далее. Младший же номер был идентификатором конкретного устройства в данном классе. Очевидно, что сочетание старшего и младшего номеров должно быть уникальным.

Файлы устройств генерировались в некотором соответствии с реальностью, но по принципу явной избыточности. Например, при наличии IDE-контроллера, поддерживающего до 4-х устройств, создавались файлы для всех теоретически подключаемых к нему дисков, даже если в наличии имелся только один. То же и с псевдотерминалами - файлов вида pty* в каталоге /dev можно было обнаружить немерянно (и понятно, почему - ведь каждый запущенный в X-сессии экземпляр эмулятора терминала вроде xtrem требовал своего такого устройства). В результате каталог /dev приобретал объем просто необозримый.

И тем не менее, подчас наличных файлов оказывалось недостаточно для представления всех нужных устройств. И тогда пользователю приходилось их создавать самостоятельно. Файлы для большинства распространенных устройств можно было создать с помощью специально предназначенного сценария /dev/MAKEDEV. Однако иногда он оказывался бессильным (особенно для новых устройств, сценарием еще неучтенных), и приходилось прибегать к чисто ручному созданию файлов устройств командой mknod. Что было не так уж и трудно само по себе, но требовало знания старшего номера создаваемого устройства (младший при этом вычислялся легко).

Появление devfs избавило пользователя от этих забот. Отныне файлы устройств пересоздаются автоматически при старте системы - и только в соответствие с наличным (и поддерживаемым текущей конфигурацией ядра) железом, определяемым в ходе загрузки. Если же в ходе работы какого-либо устройства из числа поддерживаемых недостанет - соответствующий ему файл будет создан сам собой.

Более того, devfs сделала очень легким "горячее" подключение устройств (типа карт PCMCIA, USB-накопителей, цифровых камер и сканеров с этим интерфейсом).


Достаточно воткнуть USB-драйв в соответствующий разъем - и в каталоге / dev можно будут наблюдать появление соответствующего ему файла.

В настоящее время в Linux файловая система устройств постепенно заменяется системой поддержки динамического именования устройств - udev, однако использование ее не стало еще общепризнанным.

В отличие от devfs, udev - не новая поддерживаемая ядром файловая система, пусть и виртуальная, а обычная пользовательская программа (входящая в одноименный пакет). Более того, при ее использовании необходимость в поддержке devfs отпадает вообще.

Правда, для своего функционирования udev нуждается в еще одной виртуальной файловой системе - sysfs, но ее поддержка в ядрах серии 3.6.X осуществляется автоматически (а сама эта файловая система монтируется по умолчанию в каталог /sys). Основываясь на информации из которой, udev и присваивает имена всяческим устройствам (в том числе и при горячем их подключении).

Как уже говорилось, любой POSIX-системе имена файлов конкретных устройств более или менее безразличны, так как оперирует она не с ними, а с их идентификаторами. Ранее в качестве таковых выступали старший и младший номера устройства, определяющие их класс и конкретный экземпляр его. В udev же в ход пошли непосредственные идентификаторы устройств - сериальный номер винчестера, его положение на канале IDE-шины, и так далее, сочетание которых для каждого диска (раздела, и так далее) оказывается уникальным. Программа udev извлекает эти сведения из файловой системы sysfs и, руководствуясь определенными правилами, ставит им в соответствие "человеческие" имена (вроде /dev/hda и так далее).

Во FreeBSD и многих дистрибутивах Linux используется также файловая система в оперативной памяти, именуемая mfs в первом случае и tmpfs - во втором. Реализованы они по разному, но с точки зрения пользователя выглядят почти одинаково - как дисковые разделы, смонтированные в некоторые каталоги. И на самом деле они заменяют собой блочные устройства там, где требуется быстрая, но не обязательно долговременная, запись.


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

В отличие от "нормальных" файловых систем для хранения данных, mfs и tmpfs не нуждаются в создании: для ее использования достаточно факта поддержки ядром (непосредственно или в виде модуля) и монтирования в какой-либо каталог. Обычно таким каталогом выступает /tmp, содержимое которого не должно сохраняться после рестарта системы. В BSD-системах в некоторых случаях целесообразно монтирование mfs в каталог /usr/obj, предназначенный для промежуточных продуктов компиляции при сборке ядра и базовых компонентов. А в Linux одно из штатных мест монтирования tmpfs - каталог /dev/sh. В Source Based дистрибутивах имеет смысл размещать на tmpfs также каталоги для продуктов промежуточной сборки из портообразных систем.

И в заключение нужно сказать несколько слов о своппинге и разделе для него. Строго говоря, свопиинг не имеет отношения к файловым системам, однако лучшего места для этой темы я придумать не смог.

Итак, ранее неоднократно упоминалось о разделе, предназначенном для своппинга - то есть области диска, куда может выгружаться часть содержимого оперативной памяти. В Linux и BSD механизм свопирования несколько различен. В первой системе освобождение оперативной памяти происходит при ее переполнении. В системах же BSD-семейства на своп-раздел помещаются фрагменты ОЗУ, не использовавшиеся в течении определенного времени.

С точки зрения программ (и их пользователя) физическая память и раздел своппинга представляют собой единое пространство виртуальной памяти. Что особенно четко выражено в BSD, где ОЗУ может рассматриваться как своего рода кэш по отношению к виртуальной памяти.

Для того, чтобы использовать область подкачки, нужно для создать соответствующий раздел (первичный или логический - без разницы, главное - с соответствующим идентификатором, каковой для Linux swap будет 82). В BSD-системах под своппинг отводится подраздел (subpartition) внутри слайса.



Рекомендованный размер раздела подкачки во всех системах - удвоенный объем оперативной памяти. Что нынче может показаться излишеством: в машинах типичных современных конфигураций (с ОЗУ минимум 256, а то и 512 Мбайт) под Linux раздел подкачки в ходе обычной пользовательской работы практически не задействуется, а в BSD-системах используется лишь ничтожная его доля.

Тем не менее, большие объемы swap-раздела целесообразны при активном использовании временных систем в оперативной памяти - tmpfs и mfs. В этом случае при заполнении ОЗУ эти файловые системы автоматически могут быть расширены за счет раздела подкачки. Казалось бы, это - смена шила на мыло: какой смысл подменять disk based файловую систему на систему, частично размещаемую на своп-разделе (то есть также на диске)? Однако некоторый резон к тому есть: ибо в область своппинга попадают наименее используемые части ОЗУ, так что некоторый выигрыш в быстродействии операций с временными файлами сохраняется. Правда, не стоит обольщаться - выигрыш этот не очень велик, и в наиболее благоприятных условиях не превысит 10%.

Кроме выделения раздела под своппинг, требуется явным образом определить его в этом качестве и активизировать специальными командами. Поддержка виртуальной памяти - одна из жестких функций ядра и Linux, и BSD-систем. Единственное, в чем оно еще нуждается - это в указании дискового раздела в файле /etc/fstab. Впрочем, это будет темой .


Дискодробительство в Linux


В Linux создание и первичных, и логических разделов - единый процесс, выполняемый с помощью одной и той же программы. Правда, программ таких немало - для разбиения диска можно использовать:

низкоуровневую утилиту командной строки sfdisk - инструмент очень гибкий, но сложный в обращении и требующий очень большой аккуратности - все изменения дисковой разметки совершаются там в реальном времени;

интерактивную диалоговую программу fdisk - почти столь же гибкую, как и sfdisk, но более простую и, главное, более безопасную в обращении - изменения дисковой разметки происходят тут только после соответствующего подтверждения пользователем правильности своих действий;

интерактивную меню-ориентированную программу cfdisk, которая считается еще более простой в использовании, чем fdisk (для которого она служит оболочкой, т.н. front-end) и столь же безопасна с точки зрения сохранности данных;

универсальную (в теории) утилиту parted, которая может использоваться как в режиме командной строки, так и в интерактивном; она позволяет создавать не только дисковые разделы, но и файловые системы на них;

графические фронт-энды последней - qparted и gparted.

Кроме того, существуют еще и "продвинутые" дисковые менеджеры типа Disk Druid или HardDrake, а также коммерческие программы типа Partition Magic или Acronis OS Selector. Так что инструментов разбиения - масса, остается только выбрать. Поэтому, воспользовавшись правом выбора, ограничусь рассмотрением традиционных fdisk и cfdisk, а также parted, претендующей на универсальность.

Начнем с fdisk: именно им больше всего пугали в старые времена начинающих пользователей Linux, предлагая дружественные альтернативы типа Disk Druid. Однако при ближайшем рассмотрении выясняется, что ничего устрашающего в ней нет. Запускается просто:

$ fdisk /dev/hd?

где в качестве имени устройства фигурирует имя файла устройства - физического диска целиком, например для мастера на первом канале - /dev/hda. При использовании devfs (и отказе от совместимости со старой номенклатурой) можно прибегнуть к форме


$ fdisk /dev/discs/disc0/disc

или к указанию полного имени файла устройства для IDE-диска это будет выглядеть так:

$ fdisk /dev/ide/host0/bus0/target0/lun0/disc

Да и дальше - не сложнее: мы получаем в свое распоряжение некий интерфейс, требующий ввода определенной команды, исполнение которой сводится к ответу на несколько вопросов. С полным списком доступных команд можно ознакомиться благодаря прекрасной системе помощи, вызываемой командой m. Так, команда p выведет текущий список дисковых разделов с указанием их типа и размера. Далее, разделы можно создавать (командой n) или удалять (командой d), однако до команды записи изменений (w) никаких необратимых действий, могущих разрушить ранее существующие файловые системы, не последует: неудачно созданные разделы можно удалить и на их месте создать новые. И в любой момент командой q можно без всяких последствий выйти из программы.

При создании раздела средствами fdisk сначала определяется, будет он первичным (primary) или расширенным (extended). Рассмотрим сначала первый случай. При нем далее просто указывается номер раздела (от 1 до 4). В этих пределах номер может быть любым - можно сначала создать раздел 2, а потом 1, или даже весь диск отвести под раздел 4 (именно так размечались фабричным способом zip-диски, а также некоторые флэшки. Номер раздела останется на века: именно он будет идентифицировать файл устройства, соответствующий созданному разделу (например, /dev/hda2, или /dev/discs/disc1/part2).

Далее задается начальный цилиндр создаваемого раздела (по умолчанию - первый свободный, для пустого диска - просто первый). Однако никто не мешает указать любой другой цилиндр в качестве стартового (на неразбитом пространстве, разумеется). А потом - конечный цилиндр (по умолчанию - последний физический на неразбитом дисковом пространстве), или просто размер раздела в мегабайтах, например, +300M (и +, и M - обязательны, иначе объем диска окажется весьма странным). При задании размера в единицах, отличных от цилиндров, он всегда будет округляться до ближайшего числа, кратного целому количеству последних.


Так что не следует удивляться, если вместо искомого раздела в 20 Мбайт возникнет 16-мегабайтный, а вместо 22-мегабайтного - раздел в 24 Мбайт.

При создании расширенного раздела все происходит точно также - задание номера (очевидно, что в том же диапазоне 1-4), указание начального цилиндра и конечного (или - объема в мегабайтах). Однако это - еще полдела, нужно поделить расширенный раздел на логические. И потому при следующей команде на создание раздела - n нам будет предложен уже выбор между первичным (если число последних еще не исчерпано) и логическим (ведь второй extended-раздел средствами fdisk создать нельзя):

Command (m for help): n Command action l logical (5 or over) p primary partition (1-4)

Дальше же логический раздел создается аналогично первичному.

Для каждого вновь создаваемого средствами fdisk первичного раздела по умолчанию устанавливается идентификатор типа файловой системы Linux native (83 в шестнадцатеричном исчислении), как, впрочем, и для раздела логического. Расширенный раздел также автоматически получает правильный идентификатор своего типа - 5. Однако типы эти не есть нечто неизменное. Более того, по крайней мере в одном случае изменение типа раздела - необходимость. Это потребуется также и для использования таких современных технологий, как Software RAID или LVM, о которых будет говориться позднее.

Делается это командой t, после чего запрашивается номер раздела, тип которого должен быть изменен, а затем - идентификатор желаемого типа. Полный список поддерживаемых типов файловых систем (и их идентификаторов) можно вывести командой l. Напомню, что идентификатор типа файловой системы раздела - отнюдь не файловая система, которая на нем размещается. И на разделе Linux native, как это подчеркивает название, можно создать любую файловую систему из числа тех, которые поддерживаются Linux в качестве родных (Ext2fs, Ext3fs, XFS, ReiserFS, JFS).

Теоретически fdisk позволяет присвоить созданному разделу идентификатор типа почти любой из мыслимых файловых систем - от FAT12 до Free-, Open- и NetBSD.


Однако сами по себе файловые системы средствами fdisk не создаются, и потому для разделов чуждого типа в дальнейшем потребуется их форматирование (в терминах DOS) в родной среде (например, DOS-командой FORMAT для FAT-раздела). Тем не менее, смысл в такой операции есть - резервирование места под ОС, которые будут установлены позже.

Сказанного, надеюсь, достаточно, чтобы понять: великое достоинство fdisk - исключительная гибкость: можно определить раздел строго определенного размера и точно позиционировать его на диске. Или зарезервировать в любом месте накопителя неразбитое пространство, с двух сторон окруженное созданными разделами.

Программа cfdisk описывается в литературе гораздо реже, хотя во многих дистрибутивах она пропагандируется как более удобная, чем fdisk (на мой взгляд, все как раз наоборот, но это - дело вкуса). Запустить ее можно одноименной командой, без всякого аргумента (хотя таковой в виде имени файла устройства, как в fdisk, и не возбраняется).

После запуска программы выводится информация о диске, первом физическом или том, что был указан в качестве аргумента (имя файла устройства, размер, число головок, секторов, цилиндров), таблица существующих разделов (если, кончено, они действительно существуют) и меню из следующих пунктов: Bootable, Delete, Help, Maximize, Print, Quit, Type, Units, Write. Это - для диска с существующими разделами. Если же диск не разбит (или в таблице разделов курсор зафиксирован на неразбитом пространстве), меню ограничивается пунктами Help, New, Print, Quit, Units, Write.

Смысл пунктов, думаю, понятен из их названий, как и возможности программы вообще. Замечу лишь, что здесь, как и в fdisk, до выбора пункта Write (в котором будет запрошено подтверждение действия) никаких необратимых изменений не происходит: через Quit всегда можно покинуть программу без боязни за существующие разделы и данные на них. И еще: по умолчанию размеры разделов в таблице указаны в мегабайтах. Однако через пункт Units (сиречь единицы измерения) можно переключиться на показ его в секторах или цилиндрах.



Для создания раздела выбирается пункт New, выводящий подменю: Primary, Logical, Cansel. После выбора типа раздела просто задается желаемый его размер (в мегабайтах) - и запрашивается, приписать ли раздел к началу диска или его концу. А потом остается только сохранить разбиение в таблице разделов выбором пункта Write (повторяю, с запросом подтверждения, и не просто как y, а вводом полного слова yes - дабы дать дополнительные мгновения на раздумье). То есть - все почти как в fdisk. Это и неудивительно: cfdisk по сути лишь интерфейсная для fdisk оболочка (т.н. front-end). Хотя cfdisk несколько менее гибок: например, раздел в середине неразбитого дискового пространства создать нельзя.

И, наконец, parted. Или, точнее, GNU parted, как подчеркивается в заголовке man-страницы. Эта программа предлагается в рамках проекта GNU как универсальное средство для работы не только с дисковыми разделами, но и с файловыми системами. И действительно, она позволяет не выполнить разметку диска, но и создать на разделах файловые системы, а также осуществляет проверку их целостности, удаление, перемещение, копирование и изменение размера разделов существующих.

Использоваться parted может двояким образом - в интерактивном и в командном режиме. Начнем с первого, то есть просто запустим программу одноименной командой, без опций и аргументов. В ответ она выдаст нам предупреждение об отсутствии гарантии, информацию о первом физическом диске системы - имя устройства в полной нотации devfs, данные о геометрии (цилиндры/сектора/головки), предупреждение о том, где кончается 1024 цилиндр, - и выведет приглашение командной строки в виде

(parted)

Интерфейс программы построен по принципу sh-совместимых оболочек, и весьма сходен с таковым, например, загрузчика GRUB. Поддерживаются, в частности, редактирование командной строки (обычными управляющими последовательностями, например, Control+D - удаление символа в позиции курсора, Control+H - перед оной), просмотр истории команд, автодополнение (клавишей Tab).


Действия по организации диска выполняется с помощью мнемонически прозрачных команд (print - просмотр, mkpart - создание раздела, rm - его удаление, и т.д.). Синтаксис команд - также shell-подобный: обычно требуется указание аргумента - номера устройства (Minor, в терминологии программы) и некоторых дополнительных опций (в зависимости от команды). Выход из программы - командой exit или комбинацией Control+D.

Полный список доступных команд с возможными опциями и аргументами, а также краткими, но внятными комментариями (в правильно локализованной системе - на языке установленной локали, например, русском) можно получить, введя в командной строке

(parted) help

или просто нажав Enter в ответ на приглашение. Список этот включает команды для:

выбора устройства для редактирования (select /dev/hd?);

действий с существующими разделами (print - просмотр таблицы разбиения, chech - проверка целостности файловой системы раздела, rm - удаление раздела, cp - копирование файловой системы в другой раздел, resize - изменение размера раздела, move - перемещение раздела в пределах диска);

манипуляций по разбиению диска (mkpart - создание раздела, mkpartfs - создание раздела с файловой системой заданного типа, mkfs - создание файловой системы на существующем разделе).

Подробную справку по каждой команде можно получить, введя

(parted) help имя_команды

Кроме того, справка по использованию команды будет выведена, если дать ее без аргументов и опций. И, разумеется, программа parted сопровождается документацией в форматах man и info, из которой можно получить исчерпывающие сведения о ее использовании.

В отличие от fdisk или cfdisk, в parted не предусмотрено специальной команды для записи изменений, все действия выполняются в реальном времени, без откладывания. То есть, например, команда

(parted) rm #

приведет к немедленному удалению раздела с указанным номером. Соответственно, parted требует исключительно аккуратного обращения. Однако в обмен на это предоставляет, во-первых, исключительную гибкость при задании размера раздела и его позиционировании.


Во-вторых, он делает доступными множество дополнительных манипуляций разделами и файловыми системами. Правда, в полном объеме - только для файловых систем Ext2fs, Ext2fs, ReiserFS и FAT16/FAT32, поддержка прочих (пока?) не реализована.

Чтобы оценить возможности parted, рассмотрим для примера процесс разбиения вновь приобретенного диска. Для чего после запуска программы сначала выбираем соответствующее устройство:

(parted) select /dev/hd?

затем командой

(parted) print

убеждаемся, что устройство это разбиению не подвергнуто, и даем команду для создания раздела:

(parted) mkpart type_part type_fs start end

Под типом раздела здесь могут выступать значения primary (для первичного раздела), extended (для расширенного) или logical (для логического раздела в последнем). Возможные значения для типа файловой системы - ext2, ext3, reiserfs, linux-swap или FAT. Можно указать также и иные поддерживаемые Linux файловые системы - xfs или jfs. Или даже hp-ufs и sun-ufs - версии файловой системы проприетарных Unix для платформ HP-PA и Sun Sparc, соответственно. Однако само по себе создание файловых систем при этом выполнено командой part не будет, о чем я скажу чуть ниже.

Начало (start) и конец (end) раздела указываются в мегабайтах, например, 0 и 3000 при создании раздела в 3 Гбайт от начала диска. И начало, и конец можно задать дробными (с точностью до третьего знака и разделителем - десятичной точкой) числами, что обеспечивает необходимую точность разбиения (при наличии калькулятора или способности к счету в уме).

Как легко понять из формата команды, раздел заданного размера может быть создан в любом месте диска (не обязательно в начале его или в конце). И раздел, созданный первым по времени (вне зависимости от положения на диске), получит номер (Minor) 1, созданный вторым (пусть и в начале диска) - Minor 2, и так далее. То есть по гибкости команда mkpart из parted ничуть не уступает программе fdisk.

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


Однако поскольку именно эта возможность делает программу parted столь универсальной, затрону ее здесь вскользь. Создание файловой системы осуществляется командой

(parted) mkfs # type_fs

где под # выступает тот самый номер (Minor) раздела, который был присвоен ему при создании. А доступные для создания файловые системы - ext2, ext3, reiserfs, linux-swap и FAT - на попытку приписать разделу, скажем, xfs, последует сообщение о невозможности сего действа. Можно надеяться, что это - явление временное, и поддержка всех нативных файловых систем для Linux будет включена в грядущие версии parted.

Дисковый раздел и файловая система на нем могут быть созданы также одной командой:

(parted) mkpartfs type_part type_fs start end

К опциям ее относится все то, что было сказано чуть выше об командах mkpart и mkfs.

Таким образом, создание разделов (и, добавлю, файловых систем) средствами программы parted в интерактивном режиме весьма просто и удобно (при должной, естественно, аккуратности). Однако основные ее преимущества проявляются при использовании в командном режиме. Чтобы прибегнуть к нему, программу parted следует запустить с указанием аргумента (имени файла дискового устройства), одной из его встроенных команд и необходимых последней опций. В итоге одной строкой типа

$ parted /dev/hda mkpartfs primary ext2 0 100 && \ parted /dev/hda mkpartfs primary linux-swap 101 1124 && \ parted /dev/hda mkpartfs primary ext2 1125 ###

можно создать полностью готовый к использованию в Linux диск - никаких дальнейших действий в этом направлении не потребуется.


Дополнительные утилиты


В заключение этой интермедии стоит сказать несколько слов об утилитах, имеющих некоторое отношение к теме дисковой разметки и файловых систем. А именно - о командах df и du, позволяющих получить информацию о свободном и используемом дисковом пространстве. Обе они - универсальны для всех POSIX-совместимых операционок, в базовый комплекто которых входят всегда (начиная с Version 1 AT&T UNIX).

Начнем с df (от disk free). Данная без опций и аргументов, она выведет информацию о использовании всех смонтированных в данный момент файловых системах в такой форме:

$ df Filesystem 512-blocks Used Avail Capacity Mounted on /dev/ad0s1a 508126 92666 374810 20% / /dev/mfs71 15806 2692 11850 19% /tmp /dev/ad0s1d 508126 34788 432688 7% /var /dev/ad0s1e 21553172 4542548 15286372 23% /usr /dev/ad0s2c 51936140 24257440 23523812 51% /home procfs 8 8 0 100% /proc

Форма вывода достаточно прозрачна: сначала идет имя файла смонтированного устройства (дискового раздела - в примере для DragonFlyBSD), далее - их размер в 512-байтных (то есть физических) блоках, затем - объем использованного и доступного дискового пространства, процент "занятости" и, наконец, точка монтирования.

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

А вот форма вывода определяется опциями команды df. Так, в качестве единиц измерения дискового пространства могут быть представлены не только физические блоки, но также килобайты, мегабайты или гигабайты: для этого потребуется указание опций -k, -m или -g, соответственно. Опция -h предписывает "человеческий" вывод в тех единицах, которые подходят по смыслу (то есть для 10-гигабайтного раздела это будет G, для 50-ме6габайтного - M, и так далее).
Причем это будут именно "истинные" килобайты, мегабайты и гигабайты, равные 1024, 1048576 и 1073741824. Однако, если заменить -h на опцию -H, вывод будет осуществлен в "супер-человеческом" формате, то есть в "деястичных килобайтах", "мегабайтах" и так далее; примерно так, как лукаво исчисляют объемы производители винчестеров.

Добавление опции -i, даст при выводе, плюс к объему еще и информацию о количестве занятых и свободных inodes, то есть числе теоретически возможных на данной файловой системе файлов. Опция -l ограничит вывод только локальными файловыми системами (без учета смонтированных по сети). А опция -t, значением которой выступает тип файловой системы, выведе только сведения о "заказанных ФС".

Теперь о du. Как следует из ее названия (от disk usage), она выводит информацию о дисковом пространстве, занимаемом файлам каталога, указанного в качестве ее аргумента, включая объем содержимого всех вложенных подкаталогов. Выглядит это примерно так:

$ du ~/soft/ 1010 soft/boot 679622 soft/

Не возбраняется в качестве аргумента и указание единичного файла:

$ du soft/pkgsrc.tar.gz 26608 soft/pkgsrc.tar.gz

По умолчанию du выводит результаты своей работы в физических блоках (512 байт). Однако, как и в случае с df, это легко изменить с помощью опции -h, которая подберет подходящие единицы измерения (в виде "истинных" *байт):

$ du -h soft/ 1010K soft/boot 664M soft/

А опция -k обеспечит просто вывод в килобайтах.

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

Если в качестве аргумента команды du указать каталог, выступающий как точка монтирования самостоятельной файловой системы, ее вывод даст информацию о дисковом пространстве, занятом на соответствующем разделе, подобно колонке Used в выводе команды df. При этом результаты, полученные той или другой командой, отнбдь не обязаны совпадать.Это связано с различными принципами работы df и du, прямо вытекающими из их названий.

Команда df, как ей и положено по имени, подсчитывает суммарный объем блоков, помеченных в суперблоке файловых систем как свободные, du же, напротив, считает объем, занятый каждым файлом, исходя из описания в его метаданных. А поскольку файловые операции в той или иной форме всегда кэшируются, легко представить себе ситуацию, когда после удаления файлов (то есть исключения их имен из записей в каталогах) соответствующего освобождения в "таблице занятости" еще не произошло, и блоки данных удаленных файлов окажутся учтены при подсчете df, но в вывод du уже не попадут.


Файловая иерархия


Одной из отличительных особенностей логического устройства файловой системы операционок POSIX-семейства является их иерархическая, или древовидная, организации (правда, как я уже говорил дерево выглядит это немного странно). То есть здесь нет, как в DOS или Windows любого рода, обозначений (например, буквенных, или каких-либо иных) для отдельных носителей и их разделов: все они включаются в единую структуру в качестве подкаталогов главного каталога. называемого корневым. Процесс подключения файловых систем на самостоятельных физических носителях (и их разделах) к корню файлового древа называется монтированием, а подкаталоги, содержимое которых они составляют, именуются точками монтирования.



Интермедия: инструменты дисковой разметки, форматирования и монтирования


Полный цикл подготовки носителя к использованию его в какой-либо POSIX-совместимой операционке включает в себя следующие стадии разбиение диска на разделы, создание на них файловых систем и их монтирование в файловой иерархии. Об инструментах для этих действий, различающихся в Linux и BSD-системах, и пойдет речь в данной интермедии.



Каталог /mnt


Каталог /mnt предназначен для монтирования временно используемых файловых систем, располагающихся, как правило, на сменных носителях. В всежеустановленной системе он обычно пуст, и структура его никак не регламентирована. Пользователю вольно создать в нем подкаталоги для отдельных видов носителей. Например, в моей системе это /mnt/cd, /mnt/dvd, /mnt/usb и /mnt/hd - для дисков CD, DVD, флэшки и съемного винчестера.

Во FreeBSD штатными каталогами для монтирования CD и дискет являются /cdrom и /floppy непосредственно в корневом каталоге. Что не вполне согласуется со стандартом, но по своему логично - в корень вынесены точки монтирования устройств, существующих (как CD ROM) или до недавнего времени существовавших (флоппи-дисковод) в любой машине.



Корневая файловая система


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

Наполнение корневой файловой системы подбирается с таким рассчетом, чтобы машина могла стартовать и сохраняла бы минимальную функциональность даже при аварийной загрузке (или в однопользовательском режиме), когда все остальные файловые системы не монтируются (и, соответственно, такие ее ветки, как /usr или /var, могут оказаться недоступными.

В соответствие с этим старт машины обеспечивается файлами каталогов /boot и /etc. В первом размещаются ядро системы - исполнимый файл "особого назначения", - и все, что требуется для его загрузки: в Linux, например, это системная карта (файл /etc/System.map), а во FreeBSD - загружаемые модули ядра. Впрочем, подчас ядро размещается непосредственно в корне файловой системы, и тогда каталог /boot может отсутствовать вовсе, а под модули ядра может отводиться каталог /modules.

Каталог /etc предназначен для общесистемных конфигурационных файлов, определяющих условия ее загрузки. Содержимое его очень сильно зависит от системы (а в Linux - еще и от дистрибутива), и потому рассматривать его здесь я не буду - к этой теме придется еще не раз возвращаться.

Минимально необходимая функциональность обеспечивается содержимым каталогов /bin и /sbin - в них собраны исполнимые файлы важнейших пользовательских и системных программ, соответственно, тех самых, которые позволят выполнить комплекс ремонтно-спасательных мероприятий и привести машину в человеческий вид после сбоя.

Разнесение системных и пользовательских программ по подкаталогам корня - достаточно условно. Ни одна из команд этих для решения пользовательских задач по настоящему не предназначена.
Просто в каталоге /bin собраны команды администрирования, к которым время от времени обращается (или может обратиться) и обычный пользователь, а каталог sbin предназначен для команд, о которых пользователю и знать-то не положено. И которыми он, в большинстве случаев, все равно не сможет воспользоваться по причине отсутствия соответствующих полномочий (например, требуемых прав доступа к файлам устройств).

Для запуска POSIX-программ (в том числе и тех, что собраны в каталогах /bin и sbin), как правило, требуется доступ к функциям общесистемных библиотек (в первую очередь - главной библиотеки glibc). И потому (почти) непременный компонент корневого каталога - подкаталог /lib, в коем они и собраны.

В Linux каталог /lib служит еще одной важной цели - в его подкаталоге (/lib/modules) собраны загружаемые модули ядра (во FreeBSD их место - каталог /boot/kernel).

Во FreeBSD каталога /lib в корневой файловой системе не обнаруживается - соответствующие компоненты здесь размещаются в /usr/lib (см. далее). Это связано с тем, что исторически во FreeBSD важнейшие общесистемные программы собирались так, что требуемые им библиотечные функции встраивались в их исполнимые файлы (так называемая статическая линковка, о которой речь пойдет в главе 14). Во FreeBSD 5-й ветки программы из каталогов /bin и /sbin линкуются динамически, то есть при отсутствии каталога /usr (а во Free это почти всегда отдельная ветвь файловой системы) они не функционируют. В компенсацию чего предусмотрен выходящий за рамки стандартов каталог /restore, содержащий те же программы, но слинкованные статически (как следует из имени каталога, единственным назначением его содержимого являются аварийно-спасательные работы).

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


Монтирование


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

$ mount /dev/hda1 /boot

смонтирует ранее созданную файловую систему в каталог /boot.

Утилита mount, как правило, безошибочно распознает поддерживаемые ею типы файловых систем (а в их числе - все нативные файловые системы Linux, все вариации на тему FAT и файловые системы CD и DVD-дисков). Если же по каким-то причинам она делать это отказывается, тип файловой системы нужно задать в явном виде с помощью опции -t, например:

$ mount -t vfat /dev/sda /mnt/usb

для монтирования USB-накопителя с файловой системой VFAT (вариант FAT, поддерживающий длинные имена и принятый в Windows, начиная с версии 95).

Команда mount в Linux - очень гибка и имеет много опций. Она позволяет смонтировать одну и ту же файловую систему в разные каталоги с помощью опции --bind. Например, tmpfs таким образом может быть смонтирована не только в каталог /dev/shm (штатное ее место с точки зрения стандарта POSIX), но и в каталог /tmp:

$ mount --bind tmpfs -t tmpfs /dev/shm ; $ mount --bind tmpfs -t tmpfs /tmp

Как уже говорилось, файловая система tmpfs не нуждается в создании: для ее использования достаточно поддержки в ядре и самого факта монтирования.

Более того, в разные точки можно смонтировать и ветвь каталога, не представляющую отдельной файловой системы. Это целесообразно, например, для совместного использования репозитория исходных текстов разными Source Based дистрибутивами.

Наконец, в качестве файловой системы можно смонтировать и отдельный файл, например, ISO-образ CD-диска, для чего служит опция --loop.

Непременное требование - каталог, выступающий в качестве точки монтирования, должен уже существовать до отдачи команды mount (создать таковой она почему-то не в состоянии - это следует сделать заблаговременно командой mkdir dirname). И желательно, чтобы он был пуст: монтирование в каталог с файлами фатальных последствий нынче не влечет (раньше - влекло, вплоть до общей паники системы), но все содержимое его станет недоступным вплоть до размонтирования файловой системы.
Правда, и никуда не денется тоже.

Отдельно стоит предостеречь от монтирования tmpfs в каталог /tmp в ходе рабочего сеанса: это вызовет мгновенный крах некоторых программ, в частности - оконной системы Икс. Как же быть, если нужно задействовать tmpfs именно в этом качестве? - спросите вы меня. На это я отвечу под занавес.

BSD-инструментарий для монтирования файловых систем отличается от Linux'ового тем, что здесь отсутствует универсальная команда mount. Вернее, она есть - но не носит универсального характера, предназначаясь только для монтирования родных файловых систем - UFS и UFS2. Умолчальная ее форма:

$ mount /dev/ad#s#? /mount_point

только их и в состоянии смонтировать. Для монтирования чуждых файловых систем из числа поддерживаемых предназначены специальные команды: mount_msdos - для FAT-разделов, mount_ext2 - для файловых систем Linux (только для Ext2fs и Ext3fs, причем в последней журналирование просто игнорируется), mount_cd9660 - для CD-дисков с файловой системой ISO9660 (и ее вариаций с расширениями RockRidge и Joliet). Тот же результат может быть достгнут и командой mount -t type_fs - но это лишь опосредованный вызов специальной команды для данного типа файловой системы.

Все варианты команды mount в BSD существенно беднее своей Linux-коллеги по возможностям. Здесь не допускается ни раздельное монтирование одной и той же файловой системы в разные точки, ни монтирование ветвей файловой системы. А монтирование файла как устройства требует некоторых дополнительных телодвижений.

Выше был описан процесс ручного монтирования файловых систем и в Linux, и в BSD. И действительно, к ручному монтированию подчас прибегать приходится. Однако постоянно используемые файловые системы (такие, как /usr, /home и так далее, не говоря уже о корне) целесообразно монтировать автоматически в ходе загрузки машины. За этот процесс отвечают соответствующие системы инициализации. А вот то, что должно монтироваться, описывается в конфигурационном файле /etc/fstab.

Формат его одинаков во всех POSIX-операционках, представляя собой простую базу данных, строки которой описывают каждое требующее монтирования устройство, а поля - следующие (разделитель полей - пробел или пробелы в любом количестве, а также символы табуляции):



имя файла устройства (в Linux с использованием devfs его лучше указывать соответственно номенклатуре файловой системы устройств);

точка монтирования;

тип файловой системы;

опции монтирования (их много, по умолчанию в большинстве случаев стоит значение default);

dump и pass - разрешают/запрещают резервноет копирование (дамп) файловой системы и ее проверку; реальное значение нынче почти потеряли.

Указания в поле опций монтирования значения default подразумевает, в том числе, и то, что файловая система будет смонтирована автоматически при старте системы. Однако это не подходит для сменных носителей, каковых в момент загрузки может не быть в приводе. И потому в строках, описывающих CD ROM, USB-драйвы и тому подобные дивайсы, значение этого поля должно указываться как noauto. А сама по себе запись в /etc/fstab для них призвана в дальнейшем упростить процедуру монтирования: в качестве аргумента команда mount потребует только имя каталога - точки монтирования.

Для пояснения всего сказанного приведу свой файл /etc/fstab для системы Archlinux:

/dev/discs/disc0/part1 / reiserfs notail,noatime,nodiratime 0 0 /dev/discs/disc0/part3 /var reiserfs notail,noatime,nodiratime 0 0 /dev/discs/disc0/part4 /home reiserfs notail,noatime,nodiratime 0 0

Можно видеть, что в поле опций монтирования у меня приведено довольно много значений (через запятую, без пробела). К ним мы еще вернемся, нынче отмечу лишь, что опции noatime,nodiratime запрещают обновление того самого временного атрибута - времени последнего доступа, о котором говорилось ранее, и призваны несколько повысить производительность файловых операций.

По завершении использования файловой системы она в обязательном порядке подлежит размонтированию. Для постоянно смонтированных файловых систем, описанных в /etc/fstab, это делается автоматически при перезагрузке системы (или подготовке ее к выключению).

А вот файловые системы на сменных носителях перед извлечением оных должны быть размонтированы руками. Для чего служит команда umount с единственным аргументом - точкой монтирования (или именем файла устройства - без разницы, но не обоих вместе).


То есть любая из команд типа

$ umount /mnt/cd

или

$ umount /dev/cdroms/cdrom0

одинаково успешно размонтирует файловую систему на диске в CD-приводе, без чего извлечь его оттуда можно только с помощью скрепки.

По умолчанию монтирование и размонтирование файловых систем - прероготива исключительно root'а. Однако часто целесообразно разрешить эту операцию и обычному пользователю - по крайней мере, в отношении сменных носителей. В Linux это достигается просто - указанием значения user в поле опций монтирования соответствующей строки файла /etc/fstab, например, для CD:

/dev/cdroms/cdrom0 /mnt/cd iso9660 ro,user,noauto,unhide 0 0

В BSD - несколько сложнее: во-первых, нужно в принципе разрешить монтирование устройств пользователю, что делается директивой

$ sysctl vfs.usermount=1

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

И в заключение - об активизации свопиинга. Swap-раздел не несет на себе никакой файловой системы и потому в монтиоровании не нуждается. Однако его качество должно быть задано явным образом специальной командой, например:

mkswap /dev/hda2

Здесь нужно быть внимательным: применение этой команды к разделу со всамделишней файловой системой приведет к уничтожению последней (и, соответственно, всех ее данных).

В монтировании своп-раздел также не нуждается, вместо этого его нужно активизировать:

$ swapon /dev/hda3

При старте машины активация свопа происходит автоматически, при наличии в файле /etc/fstab строки вида:

/dev/discs/disc0/part2 swap swap defaults 0 0

При наличии в машине двух дисков область своппинга целесообразно разделить между ними - это несколько способствует быстродействию. Для чего в /etc/fstab вносится уже две строки:

/dev/discs/disc0/part2 none swap sw,pri=1 0 0 /dev/discs/disc1/part1 none swap sw,pri=1 0 0

Здесь важна опция pri, значением которой выступает приоритет swap-раздела. Причем сама по себе цифра роли не играет - лишь бы приоритеты для swap-разделов обоих дисков были равны.

Обратной процедуре - дезактивации области своппинга, - служит команда

$ swapoff /dev/hda3

Она также выполняется автоматически при перезагрузке или подготовке к выключению.


Принципы построения иерархии каталогов


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

Такое положение дел затрудняет сочинение кросс-платформенных приложений. И потому существует и активно развивается проект стандартизации файловой иерархии - FHS (Filesystem Hierarchy Standard), основополагающий документ которого ныне доступен в русском переводе (за что спасибо Виктору Костромину).

Проект FHS был направлен первоначально на упорядочивание структуры каталогов в многочисленных дистрибутивах Linux. Позднее он был приспособлен для других Unix-подобных систем (в том числе и BSD-клана). И ныне предпринимаются активные усилия к тому, чтобы сделать его стандартом для POSIX-систем не только по имени, но и фактически.

Стандарт FHS покоится на двух основополагающих принципах - четком отделении в файловой иерархии каталогов разделяемых и неразделяемых, с одной стороны, и неизменяемых и изменяемых - с другой.

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

Суть противопоставления неизменяемых и изменяемых каталогов легко пояснить на примере. Так, те же общие пользовательские программы по природе своей должны быть неизменяемыми (вернее, доступными для модификации только администратору системы, но не самому пользователю, применяющему их в своей работе). В то же время эти программы при своей работе генерируют не только файлы данных, скажем, тексты или изображения (изменяемая их природа ясна без комментариев), но всякого рода служебную информацию, типа log-файлов, временных файлов и тому подобного).
Каковая и должна группироваться в каталогах, отделенных от собственно исполнимых файлов программ, необходимых для их запуска библиотек, конфигурационных файлов и т.д.

Тем не менее, не смотря на активное продвижение во многих дистрибутивах Linux из числа наиболее распространенных, статуса истинного стандарта FHS не обрел. Существует немало дистрибутивов Linux, не использующие некоторые его положения. А с традиционной файловой иерархией BSD-систем он соотносится лишь частично.

И причина - в том, что FHS игнорирует еще одно противопоставление, очень важное для пользователя: противопоставление легко восстановимых частей файловой системы, и тех ее компонентов, которые восстановимы с трудом или невосстановимы вообще.

К первым, как ни странно, можно отнести саму базовую систему: ведь переустановка ее с дистрибутивного носителя, в случае фатального краха, дело не столь уж сложное. К трудновосстановимым частям файловой системы, очевидно, относятся пользовательские данные: даже в случае регулярного их резервирования (а многие ли пользователи столь аккуратны?) развертывание их из архивов потребует немалого времени (и почти неизбежно повлечет некоторые потери).

Кроме того, в BSD-системах и Source Based дистрибутивах Linux к трудновосстановимым каталогам я отнес бы все, связанное с пакетным менеджментом - дерево портов FreeBSD или pkgsrc в NetBSD (и системах, его заимствовавших), их аналоги в дистрибутивах Linux, собственно исходники портированных программ, да и исходные тексты системы тоже. Ибо, даже если все это имеется на дистрибутиве, эти компоненты файловой системы, как правило, поддерживаются пользователем в актуальном состоянии путем синхронизации по Сети с серверами проекта (иначе их использование лишено смысла). И их утрата повлечет как временные (особенно при модемном подключении), так и финансовые (мало кто является счастливым обладателем бесплатного доступа в Интернет) потери.

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


RAID и LVM


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

Как и средства разметки, инструменты слияния дисков в массивы существенно различны в Linux и BSD-системах. А технология LVM вообще свойственна только первой ОС.

Как это в обычае в Linux, программный RAID любого выбранного уровня можно создать более чем одним способом - конкретно, двумя. Однако на каком бы способе мы ни остановились, и какой бы RAID не выбрали, в любом случае потребуется выполнение некоторых условий и некоторый комплекс однотипных действий.

Первое условие, разумеется, - физическое наличие более чем одного диска. Причем очевидно, что число их для линейного режима значения не имеет, а для level 0 предпочтительно четное количество. Опять же повторюсь: при линейном режиме порядок подключения дисков к контроллерам большой роли не играет, при выборе же нулевого RAID'а желательно разнести их на разные контроллеры.

Далее, на дисках необходимо создать (средствами fdisk, cfdisk, parted или любыми дистрибутив-специфичными утилитами) два раздела и присвоить соответствующий идентификатор - fd (в шестнадцатеричной нотации), который так и называется - RAID Auto detection. В принципе, это не обязательно, но здорово упрощает жизнь.

Теперь - ядро системы: для использования программного RAID'а в его конфигурации должны быть включены соответствующие опции в пункте Multi-device support главного меню, генерируемого по команде

$ make menuconfig

А именно:

общая поддержка "многочленных" устройств (Multiple devices driver support (RAID and LVM));

общая поддержка RAID;

поддержка предполагаемого режима - линейного (Linear (append) mode) или параллельного (RAID-0 (striping) mode).

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

Теперь можно приступать к созданию RAID-массива. Для чего потребуется соответствующие инструменты, объединяемые в один из двух пакетов - традиционный raidtools и более новый mdadm.

Первый многократно описан. Существует фундаментальный The Software-RAID HOWTO (hThe Software-RAID HOWTO), написанный Якобом Остергардом (Jakob Ostergaard) и переведенный на русский языкрусский язык Максимом Дзюманенко. Немало внимания RAID-массивам уделил в своей серии публикаций на сайте IBM-Linux Дэниэл Роббинс (часть 1 - http://www-106.ibm.com/developerworks/linux/library/l-raid1/index.html, часть 2 - http://www-106.ibm.com/developerworks/linux/library/l-raid2/index.html). И все эти документы посвящены исключительно использованию инструментария raidtools. Котрый, кстати, имеет своим местопребыванием сайт Red Hat: http://people.redhat.com/mingo/raidtools).

А вот о mdadm сведения можно почерпнуть только из его штатной документации . Русскоязычных его описаний мне не встречалось. Главное же, mdadm много превосходит raidtools с точки зрения удобства употребления (в очередной раз вынужден подчеркнуть - я рассуждаю с позиций пользователя, а не администратора сервера).

Итак, mdadm. Далеко не факт, что он имеет место быть в вашем дистрибутиве. Не беда - его всегда можно скачать - либо с автоского сайта (http://www.cse.unsw.edu.au/%7Eneilb/source/mdadm/, либо с канонического сайта Linux (http://www.kernel.org/pub/linux/utils/raid/mdadm/) в виде тарбалла исходников. Обращение с которым, после обычной распаковки, столь же своеобычно - последовательность команд make и make install (обратим внимание - программа столь проста, что в предварительном конфигурировании посредством ./configure не нуждается).



По завершении установки мы обнаруживаем единственный исполняемый бинарник /sbin/mdadm (изменить каталог для него можно, залезши руками в path2/mdadm_src_dir/Makefile, но - нужно ли? в каталоге /sbin программе такого рода самое место) и пару относящихся к нему man-страниц (mdadm.conf и mdadm), содержащих вполне достаточно информации для того, чтобы приступить к делу создания собственного RAID'а.

Нетрудно догадаться, что раз из всего пакета в итоге образовался только один бинарник, именно его и следует запустить для создания массива. Для образования RAID'а команда mdadm требует одной из двух опций: -C (эквивалент --create) или -B (сиречь --build) - в обоих случаях обратите внимание на регистр краткой формы. В чем разница между ними?

Опция -B создает массив без собственного суперблока. Что для пользователя снимает ряд преимуществ инструмента mdadm - и потому к этой опции мы возвращаться не будем. А вот опция -C этот суперблок учреждает - и ею определяется вся сила программы mdadm.

Итак, опция -C. Элементарная логика подсказывает, что она, будучи основной, требует аргумента - имени файла устройства, соответствующего создаваемому массиву (например, /dev/md0 или, при задействованной файловой системе устройств, /dev/md/0), а также указания некоторых дополнительных данных, как то: его уровня (режима), количества устройств в нем и, наконец, имен файлов устройств, массив составляющих. Что и достигается указанием опций --level=# (или, сокращенно, -l #) и --raid-devices=## (в краткой форме -n ##), после которой перечисляются имена файлов, вроде /dev/hda3, /dev/hdb3). В итоге простейший случай создания RAID'а параллельного режима выглядит следующим образом:

$ mdadm --create /dev/md0 --level=0 --raid-devices=2 /dev/hd[a,b]3

Для массива нулевого уровня допустимые значения опции --level также raid0 или stripe. А для массива линейного режима она примет значение linear (то есть -l linear).

Для параллельного режима дополнительно можно задать еще один параметр - размер блока "распараллеливаемых" данных (chunk - очевидно, что для массива в линейном режиме это смысла не имеет), в виде одноименной опции --chunk=значение (в килобайтах, в краткой форме -c ##).


Теоретически рассуждая, чем больше величина chunk'а, тем выше должно быть быстродействие массива. Однако практические измерения этого не подтверждают. И потому вполне можно опустить данную опцию - при этом умолчальное значение составит 64 Кбайт.

В любом случае после указанной выше команды RAID создан, в чем легко убедиться командой

$ less /proc/mdstat

Более того, он сразу же готов к использованию - на нем можно создать ту или иную файловую систему. Хотя, с другой стороны, никто не запрещает поделить его программой fdisk на разделы (по моим наблюдениям, cfdisk на это не способен).

Внимательный читатель, особенно знакомый с документацией по raidtools, спросит: пардон, а где же тут конфиг, описывающий RAID-массив? Отвечаю: при использовании mdadm, установке соответствующих идентификаторов на составляющих массив разделах (вспомним добрым словом RAID Auto detection), и, наконец, создании массива с собственным суперблоком (вот зачем нужна была опция -C) необходимости ни в каком конфиге не возникает.

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

$ mdadm --detail --scan

способна вывести информацию о существующем массиве. Достаточно перенаправить ее вывод в файл (таковым традиционно будет /etc/mdadm.conf) - и соответствующий конфигурационный файл будет создан.

Теперь время вспомнить о других опциях команды mdadm. С одной из них мы познакомились раньше - это --help для получения подсказки. Каковую, кстати, можно конкретизировать, указав эту опцию совместно с какой либо из других основных опций. Например, команда

$ mdadm --create --help

распишет нам процесс создания массива в деталях.

С другой опцией (--detail, или -D - все опции, отнесенные к числу основных, в сокращенной форме даются в верхнем регистре) мы столкнулись только что: она призвана выводить информацию о существующих массивах.


Близкий смысл имеют и опции --query и --examine (в сокращенной форме, соответственно, -Q и -E) - за деталями можно обратиться к man-странице.

А вот опции --assemble (-A) и --monitor, или --follow (-F) предназначены для управления существующим массивом. В частности, они позволяют добавить к нему новое устройство или удалить существующее. Правда, при выполнении некоторых условий. Впрочем, и об этом подробно расскажет тетя Маня, если попросить ее должным образом.

В общем, создание RAID-массива средствами mdadm - процесс очень простой (а управление им пользователю на десктопе, скорее всего, не понадобится). Так что, если нет необходимости в дополнительных возможностях, предоставляемых LVM, при наличии двух дисков есть резон им и ограничится.

Справедливости ради следует сказать пару слов и об инструментарии raidtools и способах обращения с ним. В отличие от mdadm, он требует обязательного наличия конфигурационного файла - /etc/raidtab. Причем создать его нужно (вручную, в текстовом редакторе) до запуска каких-либо команд по созданию RAID'а.

Впрочем, структура /etc/raidtab очень проста. Стоит только помнить, что каждый из перечисленных ниже пунктов выступает в отдельной строке, значения в которой отделяются пробелами или табулятором - все же база данных (хотя и простая), а не хвост собачий... Итак:

сначала указывается имя файла RAID-устройства - raiddev /dev/md0, например;

затем - уровень массива или его режим - raid-level 0 для параллельного режима или raid-level linear для линейного;

далее - количество устройств в массиве - nr-raid-disks 2,

потом - размер chunk'а в килобайтах, например, chunk-size 32; очевидно, что для линейного режима эта величина бессысленна, поэтому здесь можно поставить любое значение;

вслед за этим можно (а скорее, нужно) указать также, что массив должен нести собственный суперблок - persistent-superblock 1.

Наконец, последовательно перечисляются имена всех объединяемых устройствс их порядковыми номерами, начиная с нуля:

device /dev/hda3 raid-disk 0 device /dev/hdb3 raid-disk 1



Закончив редактирование /etc/raidtab, активизируем RAID командой

$ mkraid /dev/md0

и просмотром файла proc/ mdstat убеждаемся, что все произошло так, как и задумывалось.

Сложнее, конечно, чем использование mdadm, но не намного, не так ли? Тем более, что весь процесс создания RAID именно применительно к инструментарию raidtools в деталях расписан в перечисленных выше документах.

Главное различие между mdadm и raidtools таково (спасибо Владимиру Холманову за соответствующие комментарии): первый содержит один большой универсальный бинарник, что удобно для интерактивной работы с RAID. Пакет же raidtools содержит несколько специализированных небольших бинарников, а размер файла - важный параметр при использовании загрузочного initrd. Поэтому по традиции, в сценариях инициализации используются команды из raidtools. Даже если массив создается с помощью mdadm, после перезагрузки проблем возникнуть не должно - если для объединяемых в массив разделов был установлен идентификатор типа fd.

В BSD-системах также имеется два разных механизма создания программных RAID-массивов - классический ccd (Concanetade Disk driver) и более новый vinum. Это - не два разных набора инструментов, а именно две различные технологии, обладающие разными возможностями. В частности, vinum позволяет разместить на дисковом массиве корневую файловую систему, на что ccd не способен. Впрочем, с задаче размещения всех остальных ветвей последний справляется успешно, и к тому же проще в использовании, поэтому ниже чеь пойдет только о нем (заинтересованным в механизме vinum предлагается обратиться к FreeBSD Handbook в русском переводе или DragonFly Handbook - в оригинале).

Итак, ccd - драйвер слияния дисков. Средство, как я уже сказал, весьма древнее - man-страница датирована 1995 г., - а значит, проверенное временем. Позволяет создавать программные RAID-массивы типа нулевого (stripping) и первого (mirroring) уровней.

Как уже было сказано, ccd не позволяет разместить на массиве корневую файловую систему.


Поэтому перед его использованием необходимо установить нашу операционку на первый из наличных дисков, задействовав только раздел /dev/ad0s1a и оставив остальное пространство неразмеченным. После чего выполнить на обоих дисках разметку разделовдля конкатенации, что может быть выполнено двумя способами. Согласно первому, в соответствие с заветом дедушки Ленина, прежде чем объединиться, следует решительно размежеваться, согласно второму - как раз наоборот.

Суть второго способа - интуитивно понятна (и аналогична построению RAID'а в Linux с помощью mdadm): два дисковых раздела одинакового объема сливаются воедино, а потом это объединенное пространство, воспринимаемое как единый слайс, делится на разделы под нужные файловые системы. Первая же схема выглядит более сложной - сначала деление слайсов на обоих дисках на симметричные разделы под будущие файловые системы, а потом попарное их слияние. Именно на втором способе мы и задержим свое внимание.

Итак, на каждом диске требуется создать по слайсу на всем свободном пространстве (объем их должен быть примерно равным), а уж эти слайсы побить на попарные (и равновеликие) разделы, которые после конкатенации составят ветви /var, /usr, /home и все, которые еще планируется (например, /usr/ports и /usr/ports/distfiles).

Разметку слайсов можно выполнить двумя способами - через sysinstall (BSD Installer в DragonFlyBSD) или вручную. С первым способом все понятно - однако он не всегда желателен (а иногда и не проходит). И потому впору вспомнить о наших упражнениях по ручной разметке диска в предыдущем параграфе - именно здесь гибкость fdisk и disklabel оказываются востребованными.

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

$ fdisk -i /dev/ad0

а второй - как единый слайс (напомню, что подвергаемые конкатенации диски желательно разнести на разные IDE-контроллеры)



$ fdisk -I /dev/ad2

Далее, вооружившись bsdlabel (или disklabel), запускаемой с опцией -e, калькулятором командной строки bc и, конечно же, man (8) bsdlabel, на первом (/dev/ad0s1) диске, в дополнение к имевшимся

a: 524288 0 4.2BSD 2048 16384 32776 b: 2074624 524288 swap c: 156301488 0 unused 0 0

дописываем строки, определяющие полуразделы под будущие файловые системы, например, /var, /usr и /home. В результате получаем:

d: 524288 2598912 4.2BSD 0 0 0 e: 10240000 3123200 4.2BSD 0 0 0 f: 142938288 13363200 4.2BSD 0 0 0

После этого обращаемся ко второму диску (/dev/ad2s1), на котором создаем парные к первому разделы под swap, /var, /usr и /home (того же размера, что и на первом диске), что в итоге дает:

b: 2074624 0 swap c: 156301312 0 unused 0 0 # "raw" part, don't edit d: 524288 2074624 4.2BSD 0 0 0 e: 10240000 2598912 4.2BSD 0 0 0 f: 142938112 12838912 4.2BSD 0 0 0

Теперь наступает время конкатенации партиций - и для этого имеется специальная утилита ccdconfig. Вооружась соответствующей man-страницей - man (8) ccdconfig, выясняем, что и эту процедуру можно проделать двумя разными способами. Правда, оба требуют перехода в однопользовательский режим - теперь уже обязательно, если мы не сделали этого ранее.

Первый способ - последовательный запуск ccdconfig для каждой пары сливаемых партиций примерно таким образом:

$ ccdconfig ccd0 128 none /dev/ad0s1d /dev/ad2s1d $ ccdconfig ccd1 128 none /dev/ad0s1e /dev/ad2s1e $ ccdconfig ccd1 128 none /dev/ad0s1f /dev/ad2s1f

Где ccd# - имя создаваемого RAID-устройства, 128 (для примера - это умолчальное значение) - размер (в Кбайт) chunk'ов, флаг none отменяет зеркалирование (то есть создает именно sripped-массив; чтобы сделать массив уровня 1, потребовалось бы указать флаг CCDF_MIRROR или его шестнадцатеричное значение - 004). Ну а аргументы понятны - это имена файлов партиций, которые подвергаются конкатенации.

В результате в каталоге /dev будут автоматически созданы новые устройства - /dev/ccd0, /dev/ccd1, /dev/ccd2 (речь идет о FreeBSD веnrи 5.X, использующей файловую систему устройств; в 4-й ее ветке и в DragonFlyBSD эти устройства потребовалось бы предварительно создать скриптом /dev/MAKEDEV или командой mknod), а в каталоге /etc возникнет конфигурационный файл ccd.config.



Второй способ - создать предварительно конфигурационный файл /etc/ccd.conf ( которому на самом деле можно дать произвольное имя и поместить где угодно) в текстовом редакторе, и описать в нем объединяемые примерно таким образом:

# ccd ileave flags component devices ccd0 128 none /dev/ad0s1d /dev/ad2s1d ccd1 128 none /dev/ad0s1e /dev/ad2s1e ccd2 128 none /dev/ad0s1f /dev/ad2s1f

После чего запустить ту же утилиту конфигурации следующим образом:

$ ccdconfig -C

в результате чего все необходимые сведения будут взяты из /etc/ccd.conf (если конфигу дали другое имя - следует явно указать его как аргумент с полным путем), устройства благополучно созданы.

Сбросить уже имеющиеся настройки ccd (если они почему-либо не устраивают) можно командой

$ ccdconfig -U

после чего они безболезненно переконфигурируются заново.

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

Итак, для начала размечаем созданные массивы:

$ bsdlabel -w /dev/ccd0 auto $ bsdlabel -w /dev/ccd1 auto $ bsdlabel -w /dev/ccd2 auto

Что даст нам на каждом из них по партиции c, к использованию непригодной. И потому повторяем процедуру в ручном режиме:

$ bsdlabel -e /dev/ccd#

что, как мы помним, вызовет текстовый редактор для прямой модификации дисковой разметки. Копируем строку, описывающую партицию c, изменяем маркирующую ее литеру (например, на d) и тип раздела (с unused на 4.2BSD). Необходимости указывать размеры блока, фрагмента и прочего - нет, эти значения будут определены при создании файловой системы (о чем - в следующих параграфах).

После создания файловых систем их остается только смонтировать - сначала во временные каталоги типа /mnt/var, mnt/usr и /mnt/home, затем переместить в них содержимое одноименных кталогов из корня, и, наконец, прописать прописать монтирование конкатенированных разделов в /etc/fstab примерно таким образом:



/dev/ccd0e /var ufs rw,noatime /dev/ccd1e /usr ufs rw,noatime /dev/ccd2e /home ufs rw,noatime

После чего следует перезагрузка и радость от обретенных RAID'ов. Причем с точки зрения быстродействия радость эта будет вполне обоснованной: измерения показали прирост скорости на типичных файловых операциях для ccd-RAID составляет от 10 до 50% против одиночного диска.

Теперь остается сказать несколько слов об инструментарии для реализации технологии LVM, имеющей место быть только в Linux (пока?).

Для использования LVM требуется поддержка ядром системы. Это достигается включением двух опций. При использовании make menuconfig в секции Multi-device support нужно включить, во-первых, поддержку Multiple devices, во-вторых - Device Mapping (это в ядре 2.6.X, в ядрах 2.4.X это называлось Logical volume manager (LVM) support).

Далее, дисковое пространство (на одном или нескольких накопителях) следует разметить в виде разделов с идентификатором Linux LVM (8e в шестнадцатеричном исчилении).

И, естественно, потребуется софт для работы с LVM. Он входит в пакет lvm (lvm2), в составе которого - три группы утилит, предназначенных для работы с физическими томами (pv*), логическими группами (lg*) и логическими томами (lv*). Так, команда pvcreate создает физические тома, команда pvscan - сообщает об наличествующих, а команда pvdisplay выводит о них полную информацию. А тройки команд vgcreate, vgscan, vgdisplay и lvcreate, lvscan, lvdisplay проделывают то же для групп томов и логических томов, соответственно.

Как и положено уважающим себя Unix-программам, все компоненты пакета хорошо документированы, и с их опциями можно ознакомиться на стандартных man- и info-страницах. Вышеупомянутый LVM-HOWTO (http://tldp.org/HOWTO/LVM-HOWTO.html) содержит много информации по практическому применению этих команд (в том числе и душераздирающую историю о глупом Джо, не использовавшем LVM, и умной Джейн, без нее жизни себе не мыслившей).

Далее все требуемые действия могут быть расписаны по шагам. Первый из них - запуск команды



$ vgscan

которая отыщет все имеющиеся в наличии потенциальные физические тома, то есть разделы типа 8e и создаст необходимые файлы конфигурации - /etc/lvmtab и /etc/lvmtab.d, о чем любезно нас проинформирует.

Второй шаг - собственно превращение дискового раздела Linux LVM в физический том командой

$ pvcreate /dev/hda5

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

Третий шаг - создание из физических томов логической группы (Volume Group). Для этого потребуется команда vgcreate с именем группы в качестве первого аргумента и имени файла устройства раздела - как аргумента второго.

Имя группы - произвольно, в путях к файлам устройств физических томов при использовании devfs должна применяться полная нотация (как это вывела команда pvscan). По умолчанию тома нарезаются на физические блоки - extent'ы размером 4 Мбайт. При желании иметь другой размер блока - это можно явно задать опцией -s ##m. Резонные люди рекомендует использовать extent'ы в 32 Мбайт. То есть требуемая команда будет иметь вид вроде

$ vgcreate -s 32m all /dev/ide/host0/bus0/target0/part5

В этом случае максимальный размер любого из будущих логических томов ограничивается фантастической (пока) величиной 2 терабайта. Если же остановиться на умолчальном extent'е, предел тома составил бы всего-навсего 256 Гбайт. Именно всего-навсего - согласитесь, ныне эта величина не кажется недостижимой.

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

А полную информацию о вновь созданной группе мы получим командой vgdisplay, которая, в числе прочего, сообщит нам имя группы, режим доступа к ней и ряд других данных:

--- Volume group --- VG Name all VG Access read/write VG Status available/resizable VG # 0 MAX LV 256 ...


MAX LV Size 2 TB Max PV 256 Cur PV 1 Act PV 1 VG Size 73 GB PE Size 32 MB Total PE 2336 ... VG UUID TiYr9D-5Ub5-ordV-Zcv6-A7Eg-AIqD-1ALFe6

Четвертый шаг - собственно создание логического тома или томов, по желанию. Это - некий аналог нарезания на разделы физического жесткого диска. И осуществляется он командой lvcreate, для которой в качестве опций нужно указать размер тома и его имя (-L и -n, соответственно), а аргументом - имя ранее созданной группы. Размер тома можно указывать в гигабайтах или в любых других *байтах. И очевидно из названия, что под логический том можно отвести как весь объем группы, так и ее часть - в последнем случае у нас останется место и для других томов. Например, для создания томов под обычно обособляемые файловые системы последовательность команд примет такой вид:

$ lvcreate -L 10G -n lvusr all && \ lvcreate -L 2G -n lvar all && \ lvcreate -L 2G -n lvopt all && \ lvcreate -L 55G -n lvhome all && \ lvcreate -L 2G -n lvtmp all

создаст нам тома под все намеченные к использованию файловые системы. Имена томов, разумеется, произвольны и даны просто в мнемонически удобном виде.

Замечу, что приведенной последовательностью команд создаются логические тома с линейным соответствием физических и логических extent'ов. Предписать использование схемы чередования (striped) можно дополнительной опцией -i. А опция -I [значение] задаст размер чередующих блоков (в килобайтах). Однако это имеет смысл только при наличии двух физических дисков (да еще, как неоднократно подчеркивалось ранее, на отдельных IDE-каналах).

Теперь выполним проверку: командой lvscan отыскиваем все новообразованные логические тома, узнаем пути к файлам соответствующих им устройств, их размеры и убеждаемся в том, что тома (прекрасный каламбур, господа?) активированы

lvscan -- ACTIVE "/dev/all/lvusr" [10 GB] lvscan -- ACTIVE "/dev/all/lvar" [2 GB] lvscan -- ACTIVE "/dev/all/lvopt" [2 GB] lvscan -- ACTIVE "/dev/all/lvhome" [55 GB] lvscan -- ACTIVE "/dev/all/lvtmp" [2 GB] lvscan -- 5 logical volumes with 71 GB total in 1 volume group lvscan -- 5 active logical volumes .



А командой

$ lvdisplay /dev/all/lv*

получаем о каждом томе всю информацию, которую в силах предоставить нам система, например:

$ lvdisplay /dev/all/lvhome --- Logical volume --- LV Name /dev/all/lvhome VG Name all LV Write Access read/write LV Status available LV # 4 # open 1 LV Size 55 GB Current LE 1760 Allocated LE 1760 Allocation next free Read ahead sectors 1024 Block device 58:3

Остается пятый, последний, шаг: создание на каждом логическом томе файловой системы и ее монтирование - но тут уж никакой специфики нет.

Выше был описан пример для случая организации логических томов на одном диске. На двух и более - ничуть не сложнее. Придется только повторить команду pvcreate должное число раз - для создания на каждом физических томов (Physical Volume):

$ pvcreate /dev/hda5 $ pvcreate /dev/hdc5 ...

А при объединении их в логическую группу - указать в качестве аргументов каждый из физических томов:

$ vgcreate имя_группы /dev/hda5 /dev/hdc5

При создании же собственно логического тома с помощью опций -i и -I можно попытаться повысить производительность дисковых операций: команда вроде

$ lvcreate -i 2 -I 8 -L 60G -n lvhome имя_группы

создаст схему соответствия stripped между физическими и логическими extent'ами, то есть иллюзию чередования записи на два физических диска блоками (chunks) по 8 Кбайт.


Разметка диска


Как уже говорилось, понятия разметки диска несколько различаются в Linux и BSD-системах. И потому естественно, что выполняются они по разному.



Слайсы и разделы в BSD


В отличие от Linux'а, разбиение диска в BSD-системах осуществляется в два этапа и двумя отдельными программами. Сначала диск нарезается на слайсы (или создается один слайс, в режиме ли совместимости, или для эксклюзивного использования). А затем уже слайс, отведенный для BSD, разбивается на партиции. Далее речь пойдет о практике дискодробительства во FreeBSD и DragonFlyBSD, однако и в Net- или OpenBSD принципиальных отличий не будет.

Выполнению первой задачи - созданию слайса, - служит утилита fdisk. Это - еще более мощное средство работы с дисками, чем одноименная программа из Linux'а. Однако ее нельзя назвать легкой в использовании - в этом отношении она более сходна с sfdisk. Даже в man (8) fdisk среди BUG'ов отмечено, что интерфейс ее мог бы быть и подружественней. Однако на самом деле пользоваться ей не так уж страшно.

Запущенная без опций и аргументов, команда fdisk просто выдает информацию о первом физическом диске машины (вернее, о том диске, на котором размещается корневая файловая система BSD). И информацию богатую: здесь мы увидим и имя файла текущего дискового устройства (например, /dev/ad0), и сведения о его геометрии (количество цилиндров, головок, секторов на трек, блоков на цилиндр - другое дело, что к реальной геометрии они отношения не имеют, но об этом мы уже говорили), и размер физического блока.

А дальше последует информация о слайсе или слайсах, на этом диске проживающих. И тут для каждого слайса мы увидим идентификатор типа файловой системы, его размер (в блоках и мегабайтах), флаг активности (если таковой имеет место быть), данные о начале и конце (номер цилиндра/головки/сектора). Если на диске существует менее четырех слайсов, несуществующие (то есть соответствующие незаполненным записям таблицы разделов) будут помечены как UNUSED.

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

$ fdisk /dev/ar0

предоставит их для диска, подключенного к разъему IDE-RAID контроллера. Сведения эти могут показаться избыточными. Однако с помощью fdisk можно вывести и более краткую (и при этом только существенную) информацию. Чему послужит опция -s. В ответ на команду

$ fdisk -s /dev/ad#

мы получим только самое главное: имя файла устройства, количество цилиндров, головок и секторов, а также краткие сведения только о существующих (то есть не помеченных как UNUSED) слайсах - стартовый сектор, размер слайса, идентификатор типа файловой системы и флаг активности. То есть - примерно в следующем виде:

/dev/ad0: 155061 cyl 16 hd 63 sec Part Start Size Type Flags 1: 0 156301488 0xa5 0x80

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

$ fdisk -I /dev/ar0

она создаст на диске первый и единственный слайс в режиме совместимости, то есть - начиная с 63 сектора. Очевидно, что если диск перед этим был как-то разбит и содержал какие-либо данные, и разметка диска, и его содержимое будут безвозвратно уничтожены. Впрочем, такое поведение типично для всех утилит дисковой разметки в любой ОС. Правда, в отличие от одноименной утилиты из Linux, BSD'шный fdisk выполняет переразметку диска немедленно. И к тому же, тут нас даже не спросят о подтверждении своих действий, так что следует быть внимательным.

Зато много вопросов последует при использовании опции -i, которая позволяет выполнить разметку диска в интерактивном режиме. Данная с именем файла устройства в качестве аргумента, то есть в форме

$ fdisk -i /dev/ar0

она перво-наперво напомнит нам, а какой, собственно, диск подвергается надругательству и сообщит его параметры (как записанные в Disk Label, так и считанные из BIOS - в общем случае они совпадать не обязаны):

******* Working on device /dev/da0 ******* parameters extracted from in-core disklabel are: cylinders=124 heads=64 sectors/track=32 (2048 blks/cyl)



parameters to be used for BIOS calculations are: cylinders=124 heads=64 sectors/track=32 (2048 blks/cyl)

И сразу же спросит, а нет ли у нас желания скорректировать BIOS'ную геометрию диска. Ответ по умолчанию (no) очевиден, если нет сообщения о "плохой" BIOS'ной геометрии, которая к тому же совпадает с геометрией, описанной в Disk Label. А вот если факт "плохой" геометрии имеет место быть - стоит задуматься.

В большинстве случаев расхождения между "геомертрией" BIOS и Disk Label не страшно. Однако, если все же потребуется приведение их в соответствие, после положительного ответа на предложенный вопрос придется вручную задать "правильные" значения числа цилиндров, треков и секторов.

Дальнейшее занятие после исправления геометрии (или вместо нее) - это ручное создание слайсов (при существующей уже разметке сначала будет вопрошаемо, а хотим ли мы этого - с отрицательным ответом по умолчанию). Для этого сначала запрашивается идентификатор типа файловой системы (по умолчанию стоит существующий, если диск был размечен, или 0 - для диска нового) - следует указать его десятичное значение (165 для BSD-слайса). Затем - стартовый сектор (0 - при "эксклюзивной" разметке, 63 - при разметке в режиме совместимости), и размер слайса в физических, по 512 байт, блоках (при использовании всего диска, очевидно, он будет равен полному их числу, в противном случае - потребуются некоторые арифметические вычисления).

После этого будет предложено точно специфицировать начало и конец слайса. Если отказаться - они будут взяты из предыдущих определений, если согласиться - нужно будет указать первые и последние цилиндр, головку, сектор. Каковые и будут выведены в виде

sysid 165 (0xa5),(FreeBSD/NetBSD/386BSD) start 0, size 260000 (126 Meg), flag 0 beg: cyl 0/ head 0/ sector 1; end: cyl 126/ head 60/ sector 32

Подтвердив свои действия положительным ответом на вопрос

Are we happy with this entry? [n] y

можно при желании перейти к созданию второго раздела



The data for partition 2 is:

Do you want to change it? [n]

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

Do you want to change the active partition? [n]

При положительном ответе на который все сделанные изменения вступят в силу (и на ранее размеченном диске можно будет распроститься с его содержимым). Так что следует предварительно просмотреть все ранее введенное (благо, в BSD это легко сделать пролистыванием буфера истории виртуальной консоли) и при обнаружении ошибки отказаться от изменений и запустить команду fdisk по новой. Впрочем, из нее можно в любой момент выйти без последствий и стандартным образом - комбинацией клавиш Control+C.

В общем, интерактивное создание с помощью fdisk единственного слайса (хотя единственный "совместимый" слайс проще создать с помощью опции -I) не так уж и страшно. Если же слайсов потребуется несколько - придется вооружиться калькулятором (в базовом комплекте BSD есть такой - bc, запускается из командной строки, очень прост и удобен в обращении).

Хотя есть и еще один способ создания слайсов - предварительным описанием их параметров, а заодно и дисковой геометрии, в обычном текстовом файле, посредством любого привычного редактора). После чего программа fdisk запускается в форме

$ fdisk -f configfile /dev/ad#

А добавив в ней еще и опцию -t, можно предварительно протестировать правильность своей разметки, не записывая изменений на диск. Впрочем, сам я этого не проделывал, оставляя желающим для самостоятельных упражнений: все необходимые сведения, в том числе и формат config-файла, можно почерпнуть в man (8) fdisk.

Наконец, для разметки диска в эксклюзивном режиме можно обойтись без команды fdisk вообще: достаточно обнулить начальные его блоки с помощью команды dd, которая осуществляет копирование с преобразованием.


Она требует двух аргументов - имени копируемого (if - input file) файла и имени файла устройства, на которое он копируется (of - output file). Можно задать также размер блока копируемых данных и количество оных. То есть в нашем случае это будет выглядеть так:

$ dd if=/dev/zero of=/dev/ad# bs=1k count=1

или

$ dd if=/dev/zero of=/dev/ad# count=2

В обоих случаях под /dev/zero понимается т.н. "нулевое" устройство, а в качестве /dev/ad# выступает размечаемый диск, дополнительные же опции показывают, что нулями должны быть заполнены первые два физических его блока.

Созданный при помощи fdisk слайс, вне зависимости от того, "эксклюзивный" он или "совместимый", еще не пригоден к какому-либо иному использованию. Предварительно его еще нужно разбить на разделы - или хотя бы создать один раздел, ad#s1c, описывающую слайс целиком. Этой цели служит утилита disklabel (в DragonFlyBSD), или, во FreeBSD ветки 5.X, bsdlabel (с более дружественным, как говорят оптимисты, интерфейсом). Впрочем, обращение в обоими практически идентично.

Запущенные без опций (однако с обязательным аргументом в виде имени устройства), обе команды служат исключительно целям информирования о текущем положении вещей, выводя для BSD-слайса нечто вроде следующего:

$ bsdlabel /dev/ad0s1

# /dev/ad0s1: 8 partitions: # size offset fstype [fsize bsize bps/cpg] a: 524288 0 4.2BSD 2048 16384 32776 b: 2074624 524288 swap c: 156301488 0 unused 0 0 0 # "raw" part, don't edit d: 524288 2598912 4.2BSD 0 0 0 e: 10240000 3123200 4.2BSD 0 0 0 f: 142938288 13363200 4.2BSD 0 0 0

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



Среди партиций обращает на себя внимание помеченная литерой c: это тот самый "контейнер" для остальных разделов (дальняя аналогия - extended partition DOS). Ясно, что оффсет для него - нулевой, а размер равен полному количеству физических блоков диска. Для прочих партиций смещение легко (с помощью калькулятора bc) вычисляется суммированием оффсета предыдущего раздела с его размером.

В поле fstype раздела c не случайно стоит значение unused - только он имеется в наличии на свежеразмеченном с помощью fdisk носителе. Как же создать остальные необходимые партиции?

Как ни странно, один из способов - предельно прост: посредством обычного текстового редактора. Для этого bsdlabel запускается с опцией -e и аргументом - именем файла размечаемого слайса:

$ bsdlabel -e /dev/ad0s1

В ответ на что будет вызван редактор, определенный в переменной EDITOR профильного файла суперпользователя (излишне напоминать, что все операции с дисками, слайсами и разделами выполняются только от лица root'а), при отсутствии оной таким редактором будет /usr/bin/vi. И в этом редакторе мы увидим следующее:

# /dev/da0: 8 partitions: # size offset fstype [fsize bsize bps/cpg] c: 254787 0 unused 0 0 # "raw" part, don't edit

Если под файловую систему планируется отвести весь слайс целиком - достаточно в поле fstype заменить значение unused на 4.2BSD. Для создания нескольких разделов нам опять же потребуется некоторая арифметика, аналогичная примененной в интерактивном режиме программы fdisk.

То есть каждый раздел, начиная с a, должен получить значение начального оффсета (первый - соответствующий начальному блоку всего слайса, остальные - сумме оффсета и размера предыдущего), размера (опять же в блоках), типа файловой системы (для "рабочих" партиций - 4.2BSD, для раздела подкачки - swap). Поля параметров файловой системы можно не заполнять - в этом случае они примут некие "умолчальные" значения, рассчитываемые, исходя из объема раздела. А можно проставить в них нули - в таком случае параметры файловой системы будут определяться только при ее создании (то есть "форматировании" раздела).



Некоторая сложность использования fdisk, disklabel и bsdlabel обуславливает то, что во FreeBSD для подготовки носителей широко применяется (а для начинающих пользователей - рекомендуется) универсальная утилита sysinstall; в DragonFlyBSD с этой ролью более-менее справляется программа BSD Installer.

Обе они позволяют добиться поставленной цели - дисковой разметки, а заодно также создания файловой системы и ее монтирования, - быстро и с минимальным риском для имеющихся данных, а при понимании сути своих действий - сделать это (почти) также гибко, как и посредством специализированных утилит. Важно только понимать, что именно последние-то при этом и работают, тогда как sysinstall и BSD Installer - только надстройки над ними. Кроме того, BSD Installer в современном своем виде имеет некоторые ограничения функциональности. В частности, он позволяет выполнить BSD-разметку только для всего диска или для уже существующего размера с идентификатором 165: разбиение диска на слайсы для него (пока?) - задача непосильная.


Создание файловых систем


Linux поддерживает в качестве нативных несколько файловых систем, и потому для работы с каждой из них существует собственный набор инструментов: Ext2fsprogs - для файловых систем Ext2fs и Ext3fs, reiserfsprogs, xfsprogs и jfsutils - для файловых систем ReiserFS, XFS и JFS, соответственно. Каждая из этих файловых систем может быть создана командой mkfs с опцией -t, значением которой выступает желаемый тип файловой системы, и аргументом - именем файла устройства (дискового раздела).

Однако сама по себе команда mkfs - лишь оболочка, служащая для вызова специфичной команды, создающей файловую систему определенного типа: mk2efs или mkfs.ext2 - Ext2fs или Ext3fs (в последнем случае обе они требуют опции -j, предписывающей создать журнал), mkreiserfs - ReiserFS, mkfs.xfs - XFS, mkfs.jfs - JFS. Выглядит это примерно так. Команда

$ mke2fs /dev/hda1

создаст файловую систему Ext2fs на первичном разделе /dev/hda1. Команда

$ mke2fs -j /dev/hda3

создаст файловую систему Ext3fs на первичном разделе /dev/hda3. Опция -j предписывает добавление журнала) - в этом случае новая файловая система получит некоторые "умолчальные" параметры журналирования. Определить их вручную позволяет следующая форма этой команды:

$ /sbin/mke2fs -J опции_журналирования /dev/hd?#

Возможные значения опций журналирования: - size=размер, задающая объем журнального файла в мегабайтах, device=внешний_журнал для подключения новой файловой системы к журналу, ранее созданному на другом дисковом разделе, и data=режим. определяющая режим журналирования. Значения последней опции могут быть такими: journal (полное журналирование, при котором фиксируются операции не только с метаданными файлов, но и их данными), ordered (по умолчанию), при которой данные и метаданные группируются в единый блок транзакции, и writeback, в котором никакого журналирования данных не осуществляется.

Можно использовать и специальную команду /sbin/mkfs.ext3 - возможности ее идентичны таковым /sbin/mke2fs (ибо она ни что иное, как символическая на нее ссылка).
Но самое интересное - возможность преобразования существующей Ext2fs в Ext3fs простым добавлением журнала, не только без потери данных, но и без перезапуска системы (и даже без размонтирования соответствующего устройства). Делается это командой

$ tune2fs -j /dev/hd?#

Она просто добавляет файл журнала /.journal в корневой каталог модифицируемой файловой системы (если последняя не была размонтирована), или задействует для журнала скрытый inode (если перед модификацией файловая система была размонтирована). Добавлю, что обратное преобразование - еще проще, и осуществляется перемонтированием файловой системы.

Файловая система ReiserFS создается специально предназначенной для этого командой - /sbin/mkreiserfs из пакета reiserfsprogs. Для нее доступны многочисленные опции (-s для задания размера журнала, -f для принудительного переформатирования ранее существовавшей файловой системы иного типа, и т.д.), с которыми можно ознакомиться посредством man (8) mkreiserfs.

Для создания XFS также существует собственная команда mkfs.xfs (из пакета xfsprogs). В ней предусмотрено несколько опций, каждая из которых имеет ряд субопций, принимающих численные значения. Важнейшие из них:

-b, которая посредством субопции size=## позволяет задать размер блока данных в байтах, который должен быть кратен размеру страницы оперативной памяти (для платформы i386 - 4 Кбайт) и может варьировать в диапазоне от 512 до 65536 (по умолчанию - 4096); -d, определяющая параметры области данных файловой системы, такие, как количество самостоятельных областей раздела (Allocation groups, субопция agcount), или, напротив, их размер (субопция agsize); -l, специфицирующая параметры журнального файла, например, его размер (субопция size).

При использовании mkfs.xfs для достижения максимальной производительности рекомендуется в явном виде задать количество allocation groups - иначе оно будет определяться автоматически, что ведет к непроизводительным расходам ресурсов. Это делается, исходя из эмпирического расчета - одна allocation group на 4 Гбайт дискового пространства.


Далее можно установить размер файла журнала - здесь рекомендованное значение составляет 32 Мбайт. То есть для дискового раздела объемом в 20 Гбайт команда приобретет вид

$ mkfs.xfs -d agcount=5 -l size=32m /dev/hda1

Кроме всех перечисленных, команда mkfs.xfs имеет опцию -f - принудительное создание файловой системы XFS поверх любой существующей. Ее достаточно, если последняя была Ext2fs или Ext3fs. Если же XFS создается поверх ReiserFS - после этого возможны ошибки при монтировании новой файловой системы. Впрочем, то же относится и к обратной процедуре (замене XFS на ReiserFS). Это связано с тем, что команда монтирования может распознать новосозданную XFS как дефектную ReiserFS, и наоборот.

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

$ dd if=/dev/zero of=/dev/hd?#

Ждать заполнения нулями всего устройства не обязательно - достаточно дать этой команде поработать секунд 10-20, после чего прервать ее комбинацией клавиш Control+D и перейти к созданию новых файловых систем.

Наконец, и JFS имеет специфическую команду для собственного создания, которая выглялит примерно так:

$ mkfs.jfs /dev/hda7

Впрочем, тут за подробностями милости просим к страницам документации - опыта работы с JFS у меня нет.

Процесс создания файловой системы в BSD сводится к а) выделению суперблока и записи общих параметров файловой системы, б) созданию таблицы inodes (в UFS и UFS2, в отличие от некоторых современных файловых систем для Linux, все inodes создаются раз и навсегда, а не выделяются динамически, по мере надобности), и в) разметке блоков в области данных. Из за все это отвечает одна-единственная, подобно незабвенной Катерине Матвевне, программа, именуемая незамысловато - newfs.

Команда newfs требует единственного аргумента - имени файла форматируемой партиции, например,

$ newfs /dev/ad0s1a

после чего все базовые свойства файловой системы будут определены по умолчанию.


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

Опция -b определяет размер логического блока файловой системы. Минимальный размер его - 4096 байт, максимальный - 65536. Однако, как говорят, при максимально возможном размере возможны всякие неприятности, и потому надежным считается верхнее ограничение в 32768 байта. А с точки зрения здравого смысла, "умолчальное" значение в 16384 байт представляется в большинстве случаев разумным.

Опция -f устанавливает размер фрагмента блока. Рекомендуется определить его в 1/8 размера блока, что по умолчанию и составит 2048 байта. Значения в 1/4 или 1/2 блока также допустимы, но очень не рекомендуются в документации.

Опция -i очень важна - она-то косвенно и устанавливает количество записей в индексной таблице (то есть максимальное количество файлов в файловой системе). Значение этой опции дается в байтах, отводимых на элемент индексной таблицы, и должно быть кратным размеру блокового фрагмента. Значение по умолчанию - учетверенный объем оного, что определяет средний прогнозируемый размер файла (8192 байт). А максимальное количество файлов в конкретной файловой системе легко рассчитать, исходя из объема отведенной под нее партицию.

Еще одна интересная опция - это -m, значение которой указывается в процентах от суммарного объема дискового пространства отведенного на партицию. И представляет собой объем, резервируемый от записи обычными пользователями (но не root'ом - тот всегда имеет возможность записать свои действия на диск при наличии физически свободного пространства). Он определяется потому, что быстродействие файловых операций в UFS просто катастрофически падает, когда количество свободных блоков в области данных близко к исчерпанию (проверено на практике). И потому некий объем файловой системы резервируется принудительно (по умолчанию - 8%).

С этой опцией связана еще одна, -o, которая определяет алгоритм выделения свободных блоков данных при создании новых файлов.


Дело в том, что UFS в состоянии размещать их двумя способами. Первый - методом плотнейшей упаковки с целью минимизации внутренней фрагментации и экономии дискового пространства. И называется он оптимизацией по объему (опция -o принимает значение space). Второй же метод (-o time) обеспечивает быстрейшее выделение свободных блоков с целью увеличения скорости создания файлов (то есть вопреки принципу Леонида Ильича Брежнева - "экономика должна быть экономной"). Так вот, умолчальное значение -o коррелирует со значением -m: если оно больше или равно 8%, применяется оптимизация по времени, если меньше - по объему. Хотя явным образом можно указать прямо противоположные значения.

Вообще-то, все приведенные выше опции очень важны, интересны и полезны для общего образования, однако пользователю вряд ли придется к ним прибегать: их значения по умолчанию, как и почти все в BSD-системах, разумны и приемлемы в подавляющем большинстве случаев. А вот опция -U при запуске newfs по умолчанию не задействуется. Обеспечивает же она поддержку того самого механизма Soft Updates, который (парадоксально, но - правда) способствует как повышению быстродействия файловых операций, так и устойчивости файловой системы.


Стратегия разделения файловых систем


В заключение разговора о файловой иерархии следует подчеркнуть, что гарантированно на одной файловой системе (фигурально говоря, на одном дисковом разделе, хотя это и не совсем точно) должны находиться только каталоги, перечисленные в параграфе Корневая файловая система. Все же прочие каталоги - /usr, /opt, /var, /tmp и, конечно же, /home могут представлять точки монтирования самостоятельных файловых систем на отдельных физических носителях или их разделах.

Более того, в локальной сети каталоги эти вполне могут располагаться даже на разных машинах. Так, один компьютер, выполняющий роль сервера приложений, может содержать разделяемые в сети каталоги /usr и /opt, другой - файл-сервер, - вмещать все домашние каталоги пользователей, и так далее.

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

Очевидно, что корневая файловая система в составе каталогов /bin, /boot, /etc, /root, /sbin, содержащих легко восстановимые с дистрибутивного носителя и практически не изменяемые данные, должны лежать на изолированном дисковом разделе. В Linux к ним должен добавиться еще и каталог /lib. С другой стороны, при использовании в качестве загрузчика GRUB (вне зависимости от операционной системы) рекомендуется вынести на отдельный раздел каталог /boot.

В старых источниках о Linux можно прочитать о другом резоне к выделению раздела для каталога /boot, причем в самом начале диска: из-за невозможности загрузки ядра программой Lilo с цилиндра номером выше, чем 1023.
В современных версиях загрузчиков таких ограничений нет. Тем не менее, если уж раздел под /boot создается, резонно сделать его первым на диске, а непосредственно за ним разместить раздел подкачки: это добавит пять копеек быстродействия при осуществлении своппинга.

И еще из области истории: требование, чтобы корневой и загрузочный разделы были непременно первичными, также давно снято. И эти файловые системы вполне могут помещаться на логических разделах внутри Extended Partition.

Столь же ясно, что изменяемые ветви файловой системы - каталоги /var и /tmp, - должны быть вынесены за пределы корневого раздела. Причем последний, как неоднократно говорилось ранее, вообще целесообразно разместить на файловой системе в оперативной памяти (tmpfs или mfs). В случае, если каталог /var содержит подкаталоги для портообразных систем пакетного менеджмента, подобно /var/abs, /var/cache/pacman/src и /var/cache/pacman/pkg в Archlinux, они также должны образовывать самостоятельные файловые системы

Теперь - каталог /usr, содержащий либо компоненты базовой системы (как в BSD), либо - основную массу пользовательских приложений (как в большинстве дистрибутивов Linux). Он содержит легковосстановимые данны и, по хорошему, должен бы быть практически неизменяемым, и потому, безусловно, заслуживает выделения на самостоятельном разделе. Причем из его состава целесообразно вычленить, с одной стороны, подкаталоги /usr/X11R6 и /usr/local, с другой - подкаталоги для портообразных систем пакетного менеджмента: /usr/ports, /usr/pkgsrc и /usr/pkg в BSD-системах, /usr/portages в Gentoo Linux, и так далее. Причем от последних следует обособить подкаталоги для помещения исходников, скачиваемых из сети при сборке портов - /usr/ports/distfiles, /usr/pkgsrc/disfiles, /usr/portages/distfiles и подобные им.

В BSD-системах, кроме этого, из каталога /usr имеет смысл выделить подкаталоги /usr/src и /usr/obj, содержащие исходные тексты базовых компонентов (включая ядро) и промежуточные продукты их компиляции, образумемые в результате процедур make buildworld и make buildkernel.



И, наконец, каталог /home, содержащий изменяемые и часто невосстановимые данные, подлежит вынесению из корня файловой иерархии в обязательном порядке. Причем я всегда стараюсь разместить его либо на отдельном слайсе (в BSD), либо на первичном разделе (в Linux).

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

Дополнительный ее плюс - в том, что для отдельных ветвей файлового древа, в зависимости от характера размещенных на ней данных, в Linux можно подобрать физически оптимальную файловую систему. Например, для раздела под /boot нет смысла использовать что-либо помимо Ext2fs. Корневой раздел обычно рекомендуется форматировать в надежной и при этом наиболее совместимой Ext3fs. Под каталоги с огромным количеством мелких файлов, такие, как /var/abs в Archlinux, /usr/portages в Gentoo, целесообразно задействовать ReiserFS: ведь умелое обращение с мелкими файлами - это ее профиль. А в каталоге /home, где возможно появление огромных мультимедийных файлов (и который сам по себе обычно очень велик), ко двору может прийтись XFS (хотя, как показывают измерения, и ReiserFS выглядит тут вполне достойно). Такие меры могут способствовать повышению и надежности хранения данных, и быстродействию файловых операций.

Пользователи BSD-операционок безальтернативно привязаны к файловым система типа FFS. Однако и у них есть пространство для маневра. Во-первых - за счет варьирования размеров блока и фрагмента отдельных файловых систем, способствующего либо производительности дисковых операций, либо экономии дискового пространства. А во-вторых, некоторые ветви файлового древа (такие, как /tmp или /usr/obj, вопреки рекомендациям, можно безбоязненно монтировать в чисто асинхронном режиме, выиграв на этом процент-другой производительности.

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




Типовой набор каталогов POSIX-системы


Собственно говоря, для функционирования абсолютно необходимо наличие лишь одной файловой системы - той, что монтируется в корневой каталог файлового древа (своего рода аналог мирового дерева Иггдрассиль). Корневой каталог и его непременные ветви обязательно должны составлять единую файловую систему, расположенную на одном носителе - диске, дисковом разделе, программном либо аппаратном RAID-массиве, или логическом томе в понимании LVM. И в нем должны располагаться все компоненты, необходимые для старта системы и, в идеале, - ничего сверх того.

Просмотреть состав корневого каталога можно командой

$ ls -1 /

которая в любой POSIX-системе покажет некий минимальный джентльменский набор каталогов:

bin/ boot/ etc/ root/ sbin/

Именно в них собраны все файлы, без которых система не может существовать. Прочие каталоги - примерно такие:

home/ mnt/ opt/ tmp/ usr/ var/

Они а) не обязательны (по крайней мере, теоретически - практически обойтись без них трудновато), б) не каждый из них присутствует во всех системах и дистрибутивах, и в) каждый из них может быть (и часто является - если все делать по уму) точкой монтирования собственной ветви файлового древа.

Кроме этого, в большинстве случаев в корне файловой системы POSIX-совместимых ОС присутствуют еще два подкаталога:

dev/ proc/

Это обычно - точки монтирования виртуальных файловых систем - устройств и процессов, соответственно (хотя, если файловая система устройств не используется, каталог /dev обязательно должен быть компонентом корневой файловой системы. Наконец, в Linux-системах, как правило, в корне файлового древа лежит еще и каталог /lib, предназначенный для главных системных библиотек. А при использовании механизма udev неизбежным оказывается еще и каталог /sys, в который монтируется виртуальная файловая система sysfs.



Ветвь /home


Каталог /home предназначен для помещения домашних каталогов пользователей. Содержимое его никак не регламентировано, но обычно он имеет вид вроде /home/{username1,...,username#}. Хотя в крупных системах с большим количеством пользователей их домашние каталоги могут быть объединены в группы.

В каталоге /home могут располагаться домашние каталоги не только реальных, но и некоторых виртуальных пользователей. Так, если машина используется в качестве web- или ftp-сервера, можно видеть такие подкаталоги, как /home/www или /home/ftp, соответственно.



Ветвь /opt


Каталог /opt предусмотрен стандартом FHS, но реально используется не во всех дистрибутивах Linux, а в BSD-системах и вовсе отсутствует. Тем не менее, все больше программ пишется в рассчете на умолчальную инсталляцию именно в него.

Исторически каталог /opt предназначался в Linux для коммерческих приложений и всякого рода программ не вполне свободного характера. Ныне же его назначение - размещение больших самодостаточных программных комплексов, таких, как библиотека Qt, KDE со всеми его компонентами и приложениями, OpenOffice.org и тому подобных. Структура каталога должна быть такой: /opt/pkg_name. Вот как выглядит она а в моей системе (Archlinux):

$ ls -1 /opt gnome/ kde/ OpenOffice.org1.1.2/ qt/

Каждый из подкаталогов имеет собственную внутреннюю структуру:

$ ls -1 /opt/*

/opt/gnome: bin/ lib/ man/ share/

/opt/kde: bin/ etc/ include/ lib/ share/

/opt/OpenOffice.org1.1.2: help/ LICENSE LICENSE.html program/ README README.html setup@ share/ spadmin@ THIRDPARTYLICENSEREADME.html user/

/opt/qt: bin/ doc/ include/ lib/ mkspecs/ phrasebooks/ plugins/ templates/ translations/

Назначение подкаталогов внутри /opt/pkg_name легко угадывается по аналогии с /usr и /usr/local. Например /opt/kde/bin предназначается для исполнимых файлов системы KDE и ее приложений, /opt/kde/etc - для конфигурационных ее файлов, /opt/kde/include - для файлов заголовков, /opt/kde/lib - для библиотек и /opt/kde/share - для разделяемых файлов, в том числе и документации. В KDE нет документации в man-формате, если же она имеется, то (как в случае Gnome - я его не ставил, это то, что потянули Gimp и тому подобные Gtk-приложения) можно видеть подкаталог /opt/pkg_name/man.

Можно видеть, что структура каталога /opt отступает от исторически сложившейся (и внутренне обоснованной POSIX-традиции объединения в каталоги однотипных компонентов - исполняемых файлов, библиотек и так далее. И при большом количестве инсталлированных в него программ создает определенные трудности: приходится либо перегружать значениями переменную $PATH, обеспечивающую быстрый доступ к командам (о чем будет говориться в главе 12), либо создавать специальный каталог /opt/bin и помещать в него символические ссылки на исполняемые бинарники программ. Поэтому в ряде дистрибутивов Linux (например, в CRUX) каталог /opt не используется принципиально. Как, впрочем, и во всех BSD-системах. Вполне возможно, что так оно и лучше...



Ветвь /tmp


Осталось поговорить только о каталоге для хранения временных файлов - /tmp. Как и компоненты /var, они генерируются различными программами в ходе нормальной их жизнедеятельности. Но, в отличие от /var, для компонентов /tmp не предполагается их сохранения вне текущего сеанса работы. Более того, все руководства по системному администрированию рекомендуют регулярно (например, при рестарте машины) или периодически очищать этот каталог. И потому в качестве /tmp целесообразно монтировать файловые системы в оперативной памяти - tmpfs (в Linux) или mfs (во FreeBSD). Кроме того, что это гарантирует очистку его содержимого при перезагрузке, так еще и способствует быстродействию, например, компиляции программ, временные продукты которой не записываются на диск, а помещаются в виртуальный каталог типа /tmp/obj.

Во многих системах можно увидеть каталоги вроде /usr/tmp и /var/tmp. Это, как правило, символические ссылки на /tmp.



Ветвь /usr


Исторически каталог /usr предназначался для пользовательских программ и данных. Ныне эти функции распределены между каталогами /usr/local и /home (хотя и сейчас во FreeBSD по умолчанию последний представляет собой символическую ссылку на /usr/home). Каталог же /usr - не изменяемый, но разделяемый, - служит вместилищем основной части прикладных программ и всего, что к ним относится - исходных текстов, конфигурационных файлов, разделяемых библиотек, документации и тому подобного хозяйства.

Состав каталога /usr существенно различается в BSD-системах и в Linux. В первых в него помещаются только неотъемлемые части операционной системы (того, что во FreeBSD объединяется понятием Distributions). Приложения же, устанавливаемые из портов или пакетов, имеют место своей прописки подкаталог /usr/local, который может представлять отдельную ветвь файлового древа.

В Linux каталог /usr служит вместилищем всех программ (и их компонентов), штатно включенных в состав дистрибутива. А подкаталог /usr/local предназначается обычно для программ, самостоятельно собираемых из исходников.

В любом случае, обычный состав каталога /usr следующий (по выводу команды ls -1):

X11R6/ bin/ etc/ include/ lib/ libexec/ local/ sbin/ share/ src/

Как уже говорилось, подкаталог /usr/local - отдельная ветвь файлового древа, и потому будет рассмотрен отдельно же. Назначение же прочих каталогов таково:

/usr/bin и /usr/sbin предназначены для исполнимых файлов пользовательских и системных программ (здесь граница между ними еще более условна, чем в случае корневого каталога), назначение которых выходит за рамки обеспечения базового функционирования системы;

/usr/etc предназначается для конфигурационных файлов отдельных приложений;

/usr/include содержит так называемые заголовочные файлы, необходимые для линковки исполняемых файлов с библиотечными компонентами;

/usr/lib и/usr/libexec - каталоги для разделяемых библиотек, от которых зависят пользовательские приложения;

/usr/share - вместилище самых разнообразных, т.н.
архитектурно независимых, компонентов: здесь можно видеть и документацию в разных форматах, и примеры конфигурационных файлов, и данные, используемые программами управления консолью (шрифты, раскладки клавиатуры), и описание часовых поясов; /usr/src - каталог для исходных текстов; в Linux тут штатно помещаются только исходники ядра (ядер) системы, в BSD же клонах - полный набор исходников того комплекса, который во FreeBSD именуется Distributions; исходники самостоятельно собираемых программ помещать сюда, как правило, нежелательно;

/usr/X11R6 - каталог для компонентов оконной системы Икс - исполнимых файлов (/usr/X11R6/bin), библиотек (/usr/X11R6/lib), заголовков (/usr/X11R6/include), документации (/usr/X11R6/man); файлы Иксовых приложений сюда помещаться не должны (за исключением, разве что, оконных менеджеров) - их место в /usr, /usr/local или /opt, в зависимости от системы.

Кроме этого, в каталоге /usr могут обнаружиться подкаталоги /usr/var и /usr/tmp - обычно символические ссылки на соответствующие ветви корневого каталога. А в некоторых дистрибутивах Linux непосредственно в /usr помещается и основная общесистемная документация - man-страницы (в подкаталог /usr/man).

Наконец, в BSD-системах и некоторых Source Based дистрибутивах Linux (например, Gentoo) в каталоге /usr размещается подкаталог для системы управления пакетами - портов FreeBSD и OpenBSD (/usr/ports), их аналогов в других системах (/usr/portage в Gentoo). Хотя с точки зрения следования букве и духу стандарта FHS (сам он о портах и подобных системах не упоминает ни словом), более логичным местом их размещения был бы каталог /var (см. ниже) - и именно так делается в таких дистрибутивах, как CRUX и Archlinux.


Ветвь /usr/local


Как уже было сказано, ветвь /usr/local в Linux предназначена для самостоятельно собираемых из исходников (не входящих в данный дистрибутив) программ. А во FreeBSD она служит вместилищем большей части пользовательских приложений - почти всего того, что выходит за рамки Distributions и устанавливается из пакетов или портов. Соответственно этому, структура каталога в целом повторяет таковую ветви /usr (с понятными исключениями):

bin/ etc/ include/ lib/ man/ sbin/ share/

Содержимое подкаталогов также аналогично: исполнимые файлы программ (/usr/local/bin и /usr/local/sbin), их конфиги (/usr/local/etc), библиотеки, с которым они связаны, и их заголовочные файлы (/usr/local/lib и /usr/local/include, соответственно), man-страницы (/usr/local/man) и всякая архитектурно независимая всячина (/usr/local/share), в том числе и документация в иных форматах.



Ветвь /var


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

Внутренняя структура /var очень сильно меняется от системы к системе, и поэтому на деталях ее устройства я задерживаться не буду. Замечу только, что этот каталог - логичное место для помещения компонентов всякого рода портообразных систем управления пакетами, как это сделано, например, в дистрибутиве Archlinux, где под нее отведен подкаталог /var/abs (abs - Archlinux Building System).



Апология консоли


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

Казалось бы, не так давно на ниве настольных систем сосуществовали, не всегда мирно, но почти на равных, и DOS во всех ее проявлениях (MS DOS, IBM DOS и самая среди них прогрессивная и потому не вполне совместимая с прочими DR DOS), и MacOS, и милая Amiga со своей multimedia-ориентацией, и Windows всякого рода, чина и номера, и OS/2, и почти забытая Geoworks (она же GEOS), не говоря уже о сияющем NextStep. А еще туда (почти) всерьез стремились и HP-PA с ее HP-UX, и Sparc со своими SunOS и Solaris, и казавшаяся недосягаемой по производительности Alpha с Digital Unix.

Я хорошо помню авторитетные компьютерные издания первой половины 90-х, без тени улыбки обсуждавшие достоинства и недостатки всех этих ОС как платформ для настольных персоналок. Например, тесты сравнительного быстродействия WordPerfect на i386 под DOS и на Sparc под Solaris. Благо, был тогда такой ворд-процессор, реализованный для всех мыслимых и немыслимых ОСей и платформ...

И кому это все мешало? - спросили бы в Одессе. Тем не менее, в одночасье, если смотреть из сегодняшнего далека, все изменилось. Тихо и незаметно, как парторг на пенсии, почила в Бозе DOS. Оставив пару-тройку бичующих отпрысков, хватающихся за любую работу. Канули в небытие NextStep и GEOS, пошла по рукам, как стареющая красотка, Amiga, мирно дремала, как этнос в гомеостазе (Л.Н.Гумилев), OS/2. Старина Mac впал в фазу абскурации, дабы потом тихо окопаться в тесной нише издательских систем и высокой полиграфии. А титаны мира рабочих станций оставили надежду выйти на оперативный простор рабочих столов, возводя глубоко эшелонированные линии обороны на своих рубежах.


И, проснувшись в один не очень прекрасный день, пользователи увидели мелькающие на дисплеях окна, окошки, форточки: пришел отец Уыньдовс и всех подмял под себя.

Казалось, история кончилась. Жалкие потуги BeOS оттянуть на себя хотя бы симпатии, если не кошельки, пользователей, - не в счет. Для прочих же, выживших, сохранение status quo на уровне суммарных пяти процентов настольных пользователей казалось пределом мечтаний.

И тут неожиданно оказалось, что параллельно миру коммерческого софта, миру чистогана, где все покупается и все продается, существует другой мир - свободного софта и открытых исходников. Где программы пишутся для решения своих личных задач, для самообразования и поддержания профессиональной формы, для повышения престижа в собственном сообществе, а то и просто из любви к искусству и спортивного азарта. Короче говоря - Just for Fun, как сказал человек, которому суждено было стать одним из символов этого альтернативного мира.

Мир этот был почти столь же стар, как и мир коммерческий. Однако долгое время развивался он тихо и неприметно, как млекопитающие - в эру динозавров. И лишь недавно (и также исторически мгновенно) об этом мире узнали широкие круги околокопьютерной общественности. А слова Linux и Open Sources замелькали по страницам не только компьютерных, но и общественно-политических, как сказали бы при социализме, изданий. Началось явление, которое войдет в историю ушедшего тысячелетия под названием бума Linux и открытых исходников.

Разумеется, Linux не был ни единственной, ни первой, ни даже наиболее развитой системой, распространяемой свободно и открыто. Одновременно и рядом существовали и Free-, и Net-, и OpenBSD, и недавно реанимированный Hurd - это если ограничиться только Unix-подобными системами. К каковым мир свободных ОС отнюдь не сводится - время от времени появлялись и свободные операционки, отношение которых к Unix было весьма опосредованным (например, феноменальная AtheOS, ныне преобразованная в Syllable).

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


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

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

И именно эти категории людей неожиданно для себя видят, что за Окнами существует жизнь, не столь уютная и приглаженная, загадочная и порой опасная (если не для жизни - то для "железа"). Но - другая, и уже этим интересная. На мой взгляд, далеко не случайно, что Linux-бум начался именно в тот момент, когда засилье Windows казалось безграничным. Что вселает надежду и веру в род человеческий. Подобно тому, как предпоследнему авантюристу из "Территории" Олега Куваева было бы обидно, если он окажется авантюристом последним...

Прогнозировать события не возьмусь. Однако думается, что Linux-бум - он бум и есть. И со временем и сменой моды, приоритетов, жизненных установок схлынет так же в одночасье, как начался. И в итоге Linux сотоварищи останутся там, где им и место - на настольных персоналках научных работников и инженеров, школьников и студентов с соответствующими интересами, домашних компьютерных любителей. Останется и результат Linux-бума - ведь именно благодаря ему подавляющее большинство потенциальных пользователей открытых и свободных ОС узнали о самом их существовании.

Да и мир коммерческого софта никогда уже не станет прежним.


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

На текущий же момент мы наблюдаем беспрецедентный рост сообщества пользователей Linux (и прочих свободных POSIX-систем). И новопользователи Linux сейчас количественно резко преобладают над юниксоидами старого закала и энтузиастами Linux первого призыва. И все они пришли из Windows - больше неоткуда. Ведь, как говорил герой "Всей королевской рати" Уоррена, "добро можно делать только из зла, потому что больше его просто не из чего делать".

Однако за годы оконного ига выросло поколение пользователей (выросло - как пользователи, не обязательно как организмы), лихо налагающих фильтры в Photoshop'е или вращающих городские кварталы в 3DMax, но не имеющие представления не только о разбиении диска, но даже не заставшие командной строки DOS.

Это я отнюдь не в упрек: способность ряда моих знакомых применять Photoshop для анализа космоснимков или 3DMax - для построения архитектурных ансамблей вызывает у меня просто искреннее восхищение. Скорее это комплимент искусству Windows драпировать свои внутренности. Результат чего - естественное стремление Windows-мигранта и в Linux действовать в привычной среде и привычными методами. Благо, стремление это удовлетворяется интегрированными объектными средами графического режима, такими, как KDE и GNOME. Да и современные т.н. end-user oriented дистрибутивы к тому подталкивают.

Однако, как я пытался показать в главе 4, довольно быстро выясняется, что приемы работы, заимствованные из Windows, в Linux часто оказываются менее эффективными, чем традиционные инструменты Unix-систем. А большинство последних не требует для своей работы ничего, кроме классической Unix-консоли, именуемой также терминалом.


Что такое терминал


А теперь обратимся ко временам более древним - тем самым, "когда компьютеры были большими". Размером не то что с самогонный аппарат, а с цельный перегонный цех. А также - очень дорогими, как сами по себе, так и в эксплуатации, поскольку потребляли очень много электроэнергии. Счастливым обладателям таких машин (а ими являлись отнюдь не физические лица, а государственные организации, часто очень "мирного профиля", и крупные фирмы) казалось непозволительной роскошью оставлять их в индивидуальном пользовании. И потому эти машины были многопользовательскими.

Сначала пользователи приносили свои задачи в машинный зал (или, как говорили в Советской России, вычислительный центр), где они ставились в очередь, по достижении которой обрабатывались в течении определенного времени (отсюда пошло понятие машинного времени), после чего результаты забирались пользователем. Устройствами ввода при этом служили перфокарты, а вывод подавался на печатающие устройства.

Потом в качестве средств взаимодействия с машиной (и хранимыми в ней программами) стали использоваться клавиатуры, заимствованные у пишущих машинок, и дисплеи, или мониторы, созданные по аналогии с телевизором.

В результате появилась возможность оснастить рабочее место каждого пользователя сочетанием устройства ввода, с которого пользователь вводил свою задачу, и устройства вывода, на котором он мог просмотреть результат ее обсчета. Это сочетание и получило название терминала (что в данном контексте можно было бы перевести как "оконечник" - не отсюда ли родилось понятие конечного пользователя?). А для того, чтобы пользователи могли проделывать это одновременно, родилось понятие "систем разделения времени" (строго говоря, ресурсов машины вообще - ныне это чаще называют истинной многозадачностью), одной из реализаций которых и была Unix. Таким образом, понятие машинного времени утратило смысл, а все терминалы стали равны между собой. Как, впрочем, и пользователи - власть их была ограничена, каждый управлял только своим терминалом, и не имел (теоретически) никакой возможности повлиять на систему в целом.


Однако имелся среди пользователей один умник, который всех напаривал (пардон, всем управлял). Он назывался root-оператором (или просто root'ом), обладал всевластием в масштабе данной системы и реализовывал это всевластие с собственного, всевластного, терминала. Этот терминал всевластия получил название системной консоли.

В это же примерно время появились устройства хранения информации - винчестеры, названные так по аналогии маркировки первых их представителей с номенклатурой патрона для одной из популярных моделей винтовки системы Генри 30-го калибра - 0,03 дюйма, они же три линии, 7,62 мм по нашему. На винчестерах, наряду с общесистемными программами, нашлось место и для пользовательских данных. Однако пользователей было много, а машина с винчестером - одна. И чтобы пользовательские данные не путались между собою, потребовалось разграничить их друг от друга. Что и проделывалось с одного из терминалов, который был равнее других. Им была та самая системная консоль, или просто консоль, в первоначальном смысле этого термина.

Физически консоль представляла собой точно такой же терминал, как и все остальные, а ее большая равность определялась исключительно полномочиями лица, за ней сидящего. Ибо root, обладая тайным знанием - своим собственным паролем, от которого его всевластие и зависело, мог засадить в систему все хитрости свои, все меры защиты, и все такое. В частности - запрещение авторизоваться root'ом с любого другого терминала, кроме консоли. А для напаривания (опять пардон, управления) пользователями он делал так, чтобы на консоль выводились все системные сообщения (в том числе сообщения об ошибках и информация об авторизации пользователей), почему консоль root'а и получила название системной.

Потом PC уравняла пользователей в правах не хуже известного девайса полковника Кольта. За каждой такой машиной сидел один единственный пользователь, и была она самодостаточным агрегатом, имеющим собственные устройства ввода, вывода и хранения информации. Тем не менее, Unix, мигрировав на персоналки, сохранил свою многозадачную и многопользовательскую природу.Однако, если многозадачность легко реализовывалась чисто программными средствами (например. командной оболочки, что будет темой следующей главы), то как реализовать доступ нескольких пользователей (а Unix и на персоналке почти всегда имеет минимум двух пользователей - root'а и обычного) к машине, физически имеющей лишь одну комбинацию устройств ввода/вывода?


Терминалы, режимы, интерфейсы


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



О режимах


Когда машины были большие, и когда к ним начали прикручивать дисплеи в качестве устройств вывода, дисплеи эти были разными - текстовыми или графическими.

Текстовые дисплеи в терминальных комплектах использовались чаще. Их особенность в том, что они в принципе были способны выводить символы только из некоего предопределенного набора, жестко прошитого в "железе" (в ПЗУ знакогенератора). Конечно, в такие наборы входили не только текстовые (то есть алфавитно-числовые) символы, но и, например, так называемая псевдографика (уголки, линейки и т.д.), с помощью которой можно было строить некие изображения (например, элементы меню). Но важно то, что выход за пределы предопределенного набора символов был невозможен (я помню времена, когда для обеспечения вывода символов кириллицы требовалось перепрограммирование знакогенератора, что и проделывалось нашими умельцами).

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

С появлением персоналок собственно текстовые дисплеи (MDA и ранние Hercules'ы) быстро вышли из употребления. Видеосистемы IBM-совместимых машин, объединяющие в себе видеоадаптер (или, как часто говорят, видеокарту) и собственно монитор, стали графическими. Однако текстовый режим как таковой в них сохранился. Только теперь предопределенные наборы символов не прошивались в "железе", а загружались в видеокарту.
Именно программирование видеокарт и обусловило возможность создания простых способов работы с нелатинскими наборами символов (в том числе и кириллицей).

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

Часто неявным образом ставится знак равенства между текстовым режимом и режимом консольным (или режимом терминального доступа). В общем случае это неверно. Конечно, виртуальные консоли часто функционируют именно в текстовом режиме (в большинстве BSD-систем - почти исключительно в нем). Однако существует и понятие так называемой графической консоли, которое не следует смешивать с понятиями графических рабочих сред. Ибо это - самая обычная консоль, но изображения на ней (в том числе и текстовые символы) выводятся графическими средствами - то есть попиксельной прорисовкой, а не вытягиванием из предопределенного набора. Это возможно потому, что все современные (именуемые обычно VESA-совместимыми) видеокарты поддерживают так называемый линейный кадровый буфер (или Frame Buffer), допускающий прямое воспроизведение графики без использования специальных программных средств.

В принципе, с распространением жидкокристаллических мониторов, можно ожидать полного отмирания чисто текстовой консоли - уж больно неэстатично выглядит стандартный текстовый режим (80 колонок на 25 строк) на LCD-матрицах с физическим разрешением 1280x1024; не говоря уже о неэффективном использовании экранного пространства. Однако не думаю, что важность консоли от этого уменьшится. Как раз наоборот, именно режим фрейм-буфера позволяет заиграть ей дополнительными красками.

Таким образом, графическая консоль (или фрейм-консоль) знаменует собой плавный переход от чисто текстового режима к режиму графическому. Каковой в POSIX-системах может быть реализован различными способами.



Первый способ - только что упомянутая графическая консоль. Правда, до недавнего времени доступен этот способ был практически только в Linux, где требует лишь включения опции в конфигурации ядра (поддержка Frame Buffer для абстрактной VESA-совместимой видеокарты, или для одной из модельного ряда - ATI, Matrox и т.д.) и задания определенного параметра при загрузке (в большинстве современных user-ориентированных дистрибутивов это делается по умолчанию). После чего становится возможным изменение экранного разрешения в широких пределах - вплоть до 1280x1024, глубины цвета, просмотр изображений и даже видео.

Ядра NetBSD и OpenBSD, насколько мне известно, режима Frame Buffer не поддерживают. А во FreeBSD такая возможность теоретически могла быть включена, но только для фиксированного разрешения (800x600), да и на всех видеокартах, с которыми мне довелось иметь дело, выглядит это дело весьма убого.

Однако ныне в DragonFlyBSD режим графической консоли реализован ничуть не хуже, чем в Linux-консоли, позволяя выставлять произвольные (из числа поддерживаемых видеоадаптером) разрешения. И уже появились сведения о включении соответствующих патчей в ядро FreeBSD.

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

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



Второй способ реализации графического режима в свободных POSIX-совместимых операционках - с помощью специализированной библиотеки SVGAlib. Сама по себе она разработана для ОС Linux, однако скомпилированные с ее использованием бинарные приложения можно запустить на любой BSD-платформе в так называемом режиме Linux-совместимости (своего рода эмуляции, основанной на подмене системных вызовов).

Хотя запускать-то особенно и нечего: на SVGAlib основано едва ли с полдюжины приложений (в числе которых, правда, знаменитый Doom). А поскольку проект этот практически прекратил свое развитие, ожидать существенного роста программ не приходится. Так что роль SVGAlib оказывается еще более ограниченной, чем графической консоли.

Таким образом, практически единственным универсальным способом реализации графического режима в POSIX-совместимых ОС оказывается оконная система X (X Window System), или, в просторечии, просто Иксы. Ибо X - это ее имя собственное (возникшее потому, что исторически ей предшестоввала другая графическая система, именовавшаяся W), а Window в ее названии - прилагательное, призванное подчеркнуть ее оконную природу - в противоположность полноэкранным графическим системам. Ведь в прежние времена таких существовало немало (примером чему - та же SVGAlib).

Начинающими пользователями Linux Иксы воспринимаются как неотъемлемая часть этой операционной системы. Однако это не так: оконная система X создавалась совершенно независимо не только от Linux, но и от Unix вообще. И назначением ее было - обеспечивать графический режим работы на любых машинах, как-то способных вообще поддерживать графику, и поверх любых операционок.

Свободные реализации оконной системы X (а есть еще и сугубо коммерческие ее варианты, используемые в проприетарных Unix'ах) - "правильная" Xorg и "неправильная" Xfree86, - абсолютно идентичны в Linux'е, Free-, Net- и прочих BSD. И все приложения, написанные в расчете на запуск в абстрактных Иксах, будут с равным успехом работать в любой из этих операционок.



Главной составной частью Иксов вообще (и XFree86 или Xorg в частности) является программа, именуемая X-сервером (собственно, устройством X-сервера и его функциональностью и различаются разные варианты реализации оконной системы X). Она запускается непосредственно на данной машине, и взаимодействует с ее "железом" - устройствами ввода, то есть мышью и клавиатурой, и вывода - видеоподсистемой. А уже поверх X-сервера могут быть запущены разнообразные клиентские приложения. Причем, вопреки обычному пониманию терминов "клиент" и "сервер", именно они могут иметь своим местопребыванием не локальную машину, а любую другую, доступную по сети (опять же любой - локальной или глобальной).

Один из важнейших X-клиентов - программа терминального доступа, позволяющая эмулировать обычную текстовую консоль для ввода команд (и запуска любых программ вообще), почему ее и именуют еще эмулятором терминала. Таких эмуляторов существует великое множество, но минимум один - xterm, - всегда будет в распоряжении пользователя, так как входит в штатный комплект любой реализации Иксов.

Не менее важен и другой класс X-клиентов - программы управления элементами графического интерфейса, так называемые оконные менеджеры (Window Managers).Коих тоже преизрядное количество, но в состав Иксов стандартно входит лишь один - весьма архаичный twm.

Кое-что об Иксах уже говорилось во вводной части, подробностям же ее устройства будет посвящена , глава. А нам тем временем пора переходить к рассмотрению вопроса


Об интерфейсах


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

За всю историю человечества было придумано лишь два принципиально различных класса интерфейсов (между прочим, это относится не только к околокомпьютерной сфере деятельности).

Исторически первым (и, замечу, наиболее естественным) способом взаимодействия пользователя с машиной (и всеми ее потрохами) был командный интерфейс, основанный на отдаче прямых директив. Обычно он осуществляется с помощью клавиатуры, однако теоретически можно использовать и любой другой способ ввода команд - скажем, щелчком средней клавиши мыши. Именно ему, под именем CLI (Command Line Interface - интерфейса командной строки) суждено было на долгие годы стать традиционным интерфейсом Unix (а затем и POSIX-совместимых операционок вообще).

За вторым способом взаимодействия человека и машины прочно закрепилось название графического (GUI - Graphic User Interface - графического интерфейса пользователя). Название, впрочем, не строгое - а в общем случае и просто не верное: ниже будут даны примеры такого рода интерфейсов, функционирующих в текстовом режиме; и напротив - командных интерфейсов, реализуемых в режиме графическом.

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

"Совершенно верное определение" подобрать затрудняюсь, но то, что именуется графическими интерфейсами, скорее следовало бы называть интерфейсами объектными, манипуляционными или как-то в этом роде.
Хотя все эти термины неудачны - первый из-за ассоциации с ООП в понимании Грэди Буча (к коему в общем случае иметь отношения вовсе не обязан), второй - просто из-за трудновыговариемости.

Не вполне адекватен также термин "сенсуальные" интерфейсы, предложенный в свое время Максимом Отставновым. На основании того, что "звук стал их полноправной частью" (Максим Отставнов. Неимоверно важный Гном. Компьютерра, 2000, #45-46 (374-375), с. 26). До недавнего времени это - было не более, чем мечтой: почти никакой функциональной нагрузки (кроме более или менее мелодичных стонов и визгов) звук в компьютерной рабочей среде не нес. И дожить до полноценных голосовых (особенно русскоязычных) интерфейсов я не особенно рассчитывал. Хотя недавно в очередной раз был посрамлен в своем пророчестве: в KDE версии 3.4 управление голосом приобрело уже практический смысл. Однако использовать голосовые технологии для отдачи прямых командных директив будет ничуть не сложнее, чем для манипулирования объектами (на мой взгляд, даже легче).

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

Для примера: вы пытались когда-либо объяснять по телефону, как выполнить с помощью компьютера некое действие? Если да - знаете, что при использовании DOS это вполне проходило, в Windows же - получалось скверно...

Так что впредь я применительно к интерфейсам, основанным на манипулировании объектами, призываю употреблять термин "визуальные" (за неимением пока лучшего). Исключительно как антитезу интерфейсам командным, предполагающим управление прямыми директивами. Собственно же слово "графический" следует оставить за определением режимом, альтернативного режиму текстовому, как было сказано в предыдущем параграфе.



Разумеется, между используемым режимом и типом интерфейса на практике есть некоторая, хотя и не однозначная, корреляция. Так, при консольном доступе (вне зависимости - в чисто текстовом же режиме или во фрейм-консоли) пользователь фактически обречен на использование той или иной разновидности CLI. Для чего ему служат программы класса командных оболочек (shells): одна из таких программ (login shell) запускается при авторизации в системе и берет на себя ответственность за интерпретацию и исполнение вводимых пользователем директив.

Говоря об обреченности, я не имею ввиду фатального принуждения. Ибо пользователю в качестве login shell вольно использовать чуть ли не любую программу, в том числе и обеспечивающую ему нечто вроде визуального интерфейса. И программы такие имеются - знаменитый Midnight Commander тому примером. Поскольку, не смотря на свою сугубо текстовую ориентацию, в основе его лежит именно манипулирование объектами, осуществляемое комбинациями "горячих клавиш". Другое дело, что очень быстро для пользователя становится ясным, что mc не делает ничего такого, чего нельзя было бы выполнить (и обычно - гораздо быстрее и проще) прямыми командами оболочки, да и в принципе не способен ни на что большее.

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

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



Среди клиентских Иксовых программ выделяется два важнейших их типа, которые и способны обеспечить пользовательский интерфейс внутри оконной системы. Это а) эмуляторы терминала и б) оконные менеджеры.

Так вот, пользователь, запустив совместно с Иксами эмулятор терминала, оказывается в самой что ни на есть командной среде - том же login shell, что и в чистой консоли. Где он точно также, как и в консоли, может вводить командные директивы - в том числе и на запуск истинно графических приложений. С той только разницей, что функционирует его командная оболочка в Иксовом окне, а не в полноэкранном (хотя и виртуальном) терминале.

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

Существует многие множества оконных менеджеров - представление о их количестве можно получить на сайте Window Managers for X(http://xwinman.org/). Они различаются своей функциональностью: одни обеспечивают только базовые средства управления окнами (масштабирования, перемещения, переключения) и соответствующие интерфейсные элементы (кнопки минимизации, развертывания и т.д.). Другие же имеют развитые средства запуска программ, управления запущенными приложениями и т.д.

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

Традиционно интерфейсы командного стиля противопоставляются визуальным интерфейсам.Основанием чему - абсолютно разные механически (даже, я сказал бы, физиологически) приемы работы в них. Однако обращение с автомобилем и, скажем, лошадью также требует совершенно разных приемов и навыков. Что не мешает в обоих случаях достигать одной и той же цели (транспортировки чего-либо или кого-либо). С различным, правда, успехом в разных условиях.

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


Понятие виртуального терминала


Конечно, и к персоналке в принципе можно прикрутить еще один монитор и клавиатуру - и приспособления для этого имелись. Однако более простым оказалось чисто программное решение. Так в Unix появилось понятие виртуальной консоли (или виртуального терминала).

Терминологическое отступление: как уже было сказано ранее, консоль и терминал в историческом аспекте были понятиями несколько разными. Однако ныне различия между ними (почти) стерлись, и потому далее я буду использовать эти термины как синонимы. Есть и еще один вид виртуального терминала - так называемый X-терминал, реализуемый посредством специального класса программ - их договоримся называть графическими эмуляторами терминала, и речь о них будет в следующем разделе.

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

Сам факт существования виртуальных терминалов, их максимальное количество и базовые свойства (такие, как экранный буфер, возможность изменения экранных шрифтов, раскладок клавиатуры, цветовой гаммы и т.д.) определяется частью ядра системы, которая называется консольным драйвером. В Linux он так и называется - драйвер Linux-консоли. А ядра BSD-систем поддерживают возможность использования одного из нескольких консольных драйверов. Так, во FreeBSD и DragonFly по умолчанию (и - сообразно здравому смыслу) в качестве драйвера системной консоли используется syscons, в Net- и OpenBSD эту роль нынче играет wscons. Однако все три системы могут работать также с консольным драйвером pcvt - другое дело, что это не дает никаких преимуществ (и даже наоборот - скажем, русификация pcvt представляет собой занятие для садомазохистов).


Непосредственное управление свойствами терминала ( то есть, например, загрузкой конкретного шрифта или клавиатурной раскладки) управляет некий набор утилит, объединяемый в определенный (специфичный для данной ОС) программный пакет. Во FreeBSD (и DragonFly) он фактически безальтернативен, и носит то же имя, что и консольный драйвер - syscons. В Linux практически равноправно можно использовать одну из альтернатив - пакет kbd и console-tools. До некоторого времени последний считался более продвинутым, однако ныне они абсолютно идентичны по своим возможностям. И приверженность разработчиков того или иного дистрибутива одному из этих пакетов обусловлена исключительно личными пристрастиями или историческими причинами.

Как уже неоднократно говорилось, все, что существует в Unix-системе статически - суть файлы, в том числе физические или виртуальные устройства. И терминалы тут - не исключение, каждому из них соответствует свой файл в каталоге /dev. Так, физической консоли соответствует файл /dev/console, номенклатура же файлов виртуальных терминалов различна в разных ОС. Во FreeBSD и DragonFly имена их файлов имеют вид /dev/ttyv#, где # - порядковый номер терминала, начиная с нуля. В Linux (без использования devfs) файлы виртуальных терминалов именуются как /dev/tty#, причем # начинается с единицы. Файл с именем /dev/tty0 тоже есть, но он зарезервирован за той самой системной консолью, которая ныне представляет собой явление почти чисто мифическое. При задействованной же devfs файлы устройств виртуальных терминалов приобретут вид /dev/vc/#, где к номеру приложимо все сказанное выше. Хотя и в этом случае что-нибудь вроде tty# в каталоге /dev имеется на предмет обратной совместимости (это зависит от настроек демона devfsd).

Насколько мне известно, консольные драйвера POSIX-систем поддерживают до 63 виртуальных терминалов. Это связано с тем, что терминалы, как и всякие другие файлы устройств, характеризуются своими номерами - старшим (major) и младшими (minor). Старший номер класса терминальных устройств зависит от ОС, а под младшие номера зарезервированы числа с 1 до 63.


Этим и определяется максимально возможное число консолей.

Принципиальная возможность существования 63 виртуальных терминалов не означает, однако, будто бы все они на самом деле доступны пользователю. Начать с того, что виртуальный терминал требует активизации. Для чего на нем должен быть запущен какой-либо процесс. При старте системы такие процессы (команды семейства getty) запускаются для некоторого количества терминалов. В большинстве дистрибутивов Linux традиционно активизируется 6 виртуальных консолей, в последних версиях FreeBSD и в DaronFly - 8. Эти числа определены в конфигурационных файлах /etc/inittab и /etc/ttys, соответственно, и могут быть изменены в любую сторону. Правда, в большую - с некоторыми оговорками (первая - максимально возможное теоретически число консолей, о второй скажу парой абзацев ниже).

Консоли сверх умолчального количества могут быть активизированы и после загрузки системы. Для этого достаточно запустить на них какой-либо процесс. Им может быть:

процесс на тему getty, вызывающий, в конечном счете, приглашение к авторизации;

запуск программы автоматической регистрации пользователя типа qlogin;

запуск сеанса работы оконной системы X (подробности - в следующем разделе);

запуск не-Иксовой графической программы, обеспечиваемой библиотекой SVGAlib;

непосредственный запуск (почти) произвольной программы с помощью команды openvt (правда, последнее - только в Linux, насколько мне известно).

Любым из указанных способов в Linux можно открыть виртуальные терминалы с 7-го по 63-й. Во FreeBSD есть еще одно ограничение - максимальное число консолей, поддерживаемое текущей конфигурацией ядра. По умолчанию оно равно 16-ти, изменение требует реконфигурирования ядра и его пересборки.

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


Впрочем, юзеру с исключительно подоконным опытом работы не дано понять ни того, ни другого...

Потрясение это обусловлено рядом факторов. Во-первых, сама возможность открыть второй (третий, пятый, восьмятый) виртуальный терминал, авторизоваться в нем под своим пользовательским или иным другим именем (в том числе - и root'ом) и запустить любую программу, переключаясь по мере надобности между открытыми приложениями ничуть не сложнее, чем между окнами в графической среде типа Windows.

Способ переключения между виртуальными терминалами зависит от умолчальных настроек используемого консольного драйвера. В Linux и BSD'шном syscons переключение выполняется комбинацией клавиш Alt+F#, где # - номер консоли. В wscons той же цели служит чуть более сложное сочетание - Control+ Alt+F# (забегая вперед, отмечу, что она же используется во всех операционках для переключения из сеанса X в текстовую консоль).

Указанные комбинации (например, Alt+F#) для перехода между консолями не являют собой нечто предопределенное божественным промыслом. Ибо зависят исключительно от текущей раскладки клавиатуры.

Легко сообразить, что означенным способом можно получить доступ к виртуальным терминалам с 1-го по 12-й. А как быть, если вздумается установит большее их количества? - ведь более 12 функциональных клавиш на клавиатурах обычно не наблюдается...

Есть несколько способов доступа к виртуальным терминалам с произвольным номером. Например, в большинстве случаев комбинация клавиш Alt+Shift+F# обеспечивает переход к консолям с 13-й по 24-ю. Далее, в некоторых системах нажатием клавиши PrtSc можно последовательно пролистать активные консоли, начиная с текущей (а в других случаях - перейти в последнюю по счету из активизированных консолей. И, наконец, (почти) универсальный способ - команда

$ chvt #

где # - номер целевой консоли.

В Linux виртуальные терминалы абсолютно равноправны. В BSD-системах же сохранился рудимент представления о системной консоли - таковой по выступает 1-й виртуальный терминал.


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

Как говорилось в , каждый пользовательский интерактивный процесс (то есть, фигурально говоря, программа, запущенная пользователем с помощью командной директивы) связан с каким-либо виртуальным терминалом. При этом для программы различаются понятия управляющего и текущего терминала. Первый - тот, с которого программа была запущена, и с которого можно при необходимости прервать ее исполнение. На текущий же терминал выводятся результаты ее работы. Обычно управляющий и текущий терминалы совпадают, однако это не обязательно. С помощью определенных средств (того же qlogin, например, или openvt), программу можно запустить так, чтобы она исполнялась на терминале, отличном от стартового. При этом последний сохраняет свои управляющие функции.

Еще одно различие выявляется между текущей консолью и всеми прочими при запуске какой-либо программы графического режима, например, Иксов. При этом в первую очередь запускается вполне конкретная программа - X-сервер и текущая консоль как бы блокируется вплоть до выхода из Иксов (или из SVGAlib-программы). А для запущенной с нее программы активизируется новая виртуальная консоль, которая и становится текущей.

Хотя на самом деле блокировки консоли, с которой запущенны Иксы, не происходит (спасибо Тихону Тарнавскому, обратившему мое внимание на сей факт). Просто она занимается процессом, сиречь Иксами, который и выводит на нее массу своих служебных сообщений. Так что если запустить Иксы в фоновом режиме, а вывод сообщений куда-нибудь перенаправить (в log-файл или тот же /dev/null), то и эту консоль можно задействовать для нормальной работы.

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



Отметим, что использующая графику программа, запущенная из консоли с поддержкой графического режима через frame buffer, занимает только текущий виртуальный терминал, который остается для нее и управляющим.

Второе открытие, подстерегающее пользователя, приобщающегося к POSIX'ивизму, - консольный буфер экрана (или, как он называется в BSD, буфер истории). Оказывается, если вывод данной консоли не умещается на один экран - его можно "пролистать" назад и, до текущего положения, вперед, как в текстовом редакторе. Правда, одних клавиш PageUp/PageDown для этого недостаточно. В консоли Linux (и wscons) пролистывание осуществляется одной из этих клавиш при нажатом Shift. А в syscons перевод в режим "листания" буфера истории осуществляется нажатием фиксируемого переключателя ScrollLock.

Есть и еще одно отличие буфера истории консолей BSD и Linux. В первой операционке он полностью независим для каждого виртуального терминала. И, переключаясь между ними, можно листать страницы их истории, сколько вздумается (в некоторых пределах, установленных в текущей конфигурации ядра).

В Linux'е же в каждый момент времени доступен только буфер истории текущего виртуального терминала. Переключение в другую консоль активизирует ее буфер истории, но необратимо стирает историю консоли предыдущей (как любитель истории, не могу не отметить, что больший "историзм" BSD-систем проявляется и в таких мелочах).

Третий поражающий воображение фактор - возможность настроить для каждой консоли свою цветовую гамму: установить свой цвет фона и шрифта, а в syscons еще и цвет так называемого бордюра - это та самая черная каемка, памятная заставшим времена старых 14-дюймовиков без средств цифрового управления, на которых искоренить ее нельзя было никакими силами.. Так вот, и это абсолютно, казалось бы, паразитный элемент можно приспособить для использования в мирных целях - я задействую его для визуального различения консолей (например, консоль для регистрации root'а у меня всегда имеет бордюр тревожно-красного цвета).



И, наконец, четвертое: хотя виртуальные терминалы изображают собой (почти) самостоятельные машины, между ними возможен обмен данными. И служит этому любимое устройство "подоконников" - самая обычная мышь. Каковая в консоли служит не средством указательства или позиционирования курсора (в Unix-консоли текстовый курсор и курсор мыши суть вещи, совершенно друг с другом не связанные, во FreeBSD это подчеркивается даже их разным представлением на экране), а предназначена для помещения выделенных экранных фрагментов в специальный буфер обмена. Из коего они могут быть скопированы в любой активный виртуальный терминал.

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

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

О несравненных достоинствах консоли можно говорить бесконечно. Но пора переходить к разговору