Ключевые слова:fs, disk, freebsd, ufs, partition, fdisk, inode, mount, raid, cdd, (найти похожие документы)
From: Алексей Федорчук <alv@linux-online.ru.>
Newsgroups: http://www.ixbt.com
Date: Mon, 20 Nov 2004 18:21:07 +0000 (UTC)
Subject: Работа с дисками и файловыми системами в FreeBSD
Оригинал: http://www.ixbt.com/soft/freebsd03.shtmlhttp://www.ixbt.com/soft/freebsd04.shtmlhttp://www.ixbt.com/soft/freebsd05.shtmlhttp://www.ixbt.com/soft/freebsd06.shtmlhttp://www.ixbt.com/soft/freebsd07.shtmlFreeBSD: диски, слайсы, партиции
Разумеется, обойтись без sysinstall при установке FreeBSD все равно не
удастся (да и не нужно). Однако для понимания ее внутренней сущности
(а sysinstall -- это своего рода интегрирующая надстройка, front-end,
над серией низкоуровневых утилит) требуются некоторые предварительные
знания, в частности, о дисковых накопителях, дисковых разделах и
файловых системах FreeBSD. Тем более, что именно в этом отношении
FreeBSD разительно отличается не только от DOS/Windows, но и от Linux,
причем как терминологически, так и по существу.
Так что практическое знакомство с FreeBSD целесообразно начать именно
с круга вопросов, вынесенных в заглавие этой заметки, в которой будут
рассмотрены диски и дисковые разделы.
Дискобольское введение
Чтобы более не повторяться, оговорюсь сразу: большая часть того, о чем
будет говориться в этой заметке, относится к дискам с интерфейсом IDE
(ATA). SCSI-диски имеют свою специфику, но я с ними дела не имел и
собственных впечатлений на сей предмет у меня нет. Да и в контексте
настольного использования FreeBSD это становится все менее актуальным.
Хотя и тему SCSI устройств придется затронуть -- но не в отношении
дисков, а накопителей иного типа.
Для начала вспомним, что дисковые накопители во FreeBSD (как и любые
другие устройства в любой POSIX-совместимой системе) предстают перед
пользователем в виде файлов специального типа -- файлов устройств,
конкретнее -- файлов блочных устройств (то есть тех, обмен данными с
которыми осуществляется не побитно, как, скажем, с сериальными
портами, а блоками некоего фиксированного размера). Файлы эти
расположены в каталоге /dev, и номенклатура их подчиняется строгим
правилам.
Во FreeBSD 5-й ветки используется т.н. файловая система система
устройств -- devfs. Подробный разговор о ней впереди, пока лишь
минимум практических сведений.
Раньше (в ветке 4 и ниже) файлы устройств создавались с помощью
специальной утилиты (при установке системы -- автоматически) как бы
впрок, для (почти) всех теоретически возможных устройств. В результате
в каталоге /dev обнаруживалось немерянное количество файлов для дисков
и их разделов, терминалов и псевдотерминалов, и многого, многого
другого. Большая часть которого оказывалась лишней. В то же время
вполне могло не оказаться чего-то необходимого лично вам, но не
предусмотренного стандартным сценарием создания файлов устройств.
Эту проблему (на самом деле не только эту, но и многие другие) сняла
devfs. Теперь файлы каталога /dev создаются при загрузке системы
только для устройств, реально существующих -- раз, и поддерживаемых
ядром системы (конкретным, лично сконфигурированным, или типовым ядром
GENERIC). Более того, при <<горячем>> подключении устройств, таковое
допускающих, соответствующие им файлы создаются <<на лету>>.
Так вот, файлы устройств ATA-дисков именуются ad#. Как нетрудно
догадаться, аббревиатура ad происходит от ATA Disk, а # --
соответствует номеру конкретного накопителя в порядке его подключения
к IDE-разъемам. То есть
/dev/ad0 Master на 1-м IDE-канале
/dev/ad1 Slave на 1-м IDE-канале
/dev/ad2 Master на 2-м IDE-канале
/dev/ad3 Slave на 2-м IDE-канале
Во FreeBSD по умолчанию принята статичная нумерация файлов дисковых
устройств. То есть, например: файл диска Slave на 2-м IDE-канале
всегда будет носить имя /dev/ad3, даже если он является единственным в
системе. Случай, конечно, гипотетический -- реально вряд ли кому
понадобиться подключать диск таким образом. Однако важно, что при этом
в каталоге /dev установленной FreeBSD 5-й ветки будет присутствовать
только один файл устройства -- /dev/ad3. Тогда как в более старых
ветвях мы увидели бы также созданные <<про запас>> файлы /dev/ad0,
/dev/ad1 и /dev/ad2, хотя попытка обращения к ним ничего, кроме
сообщения об ошибке, и не дала бы.
В старых (но не обязательно устаревших) документах о FreeBSD можно
встретить имена дисковых устройств вида /dev/wd0 и так далее. Такая
номенклатура для IDE-дисков применялась в версиях ветки 3 и ранее.
Начиная с ветки 4, за ними закрепились имена ad#.
Диски, подключенные к дополнительному простому IDE-контроллеру
(например, реализованному на отдельной плате расширения), получают
следующие по порядку номера -- /dev/ad4, /dev/ad5, /dev/ad6, /dev/ad7.
А вот с дисками на контроллере ATA RAID (а ныне они стали почти
стандартным компонентом материнских плат) получается интереснее. Они
существуют как бы в двух ипостасях -- то есть одному и тому же
физическому устройству соответствует два файла -- /dev/ad# (где #
будет начинаться с 8 для Master'а на 1-м RAID-канале) и /dev/ar# (где
ar, как можно понять по аналогии, означает ATA RAID, а нумерация будет
начинаться с единицы). До выполнения процедуры разбиения диска оба
имени будут абсолютно равноправны, и любое из них можно будет выбрать
как объект для создания разделов. Однако после того, как разбиение
закончится, файлы устройств разделов будут образованы только на основе
имени выбранного диска.
Некоторые контроллеры ATA RAID позволяют переключать их в режим работы
обычного IDE-контроллера. В этом случае подключенные к ним диски будут
именоваться обычным для ATA-накопителей образом -- /dev/ad4 и так
далее.
Номенклатура и нумерация других ATA-накопителей (например, внутренних
Zip-драйвов) подчиняется тем же правилам, по которым обозначаются
винчестеры. За исключением ATAPI CD ROM и CD-R/RW -- файлы этих
устройств по традиции именуются /dev/acd0 и /dev/acd1 (от ATAPI CD ROM
-- а кто видел в системе больше двух таких приводов?). Причем, в
отличие от дисков, -- вне зависимости от канала, на котором они сидят,
просто в порядке подключения.
Файлы устройств SCSI-дисков именуются /dev/da# (как я предполагаю, от
direct access -- устройства прямого доступа), с нумерацией в порядке
подключения к SCSI-шине. Сами по себе SCSI-диски нас не интересуют.
Однако такие накопители, как USB flash (которые имеют все шансы стать
стандартными сменными носителями взамен флоппи-дисков), также
предстают перед системой как SCSI-диски. И соответственно первая же
подключенная к машине флэшка (вне зависимости от того, к какому
USB-разъему) получит имя /dev/da0. Причем это тот самый случай, когда
файловая система устройств создаст для нее файл <<на лету>>, в чем
легко убедиться командой
$ ls /dev/
до и после подключения USB-накопителя.
Последнее устройство дискового типа, с которым приходится иметь дело
пользователю настольной машины -- это флоппи-дисководы. Файлы их
именуются незамысловато -- /dev/fd#, где для # с большой долей
вероятности можно предполагать значение 0.
Конечно, FreeBSD поддерживает и все прочие известные типы накопителей
-- старые CD ROM с фирменными интерфейсами типа псевдо-SCSI, стриммеры
с разными интерфейсами, SCSI RAID и так далее. Однако на настольной
пользовательской машине обнаружить их нелегко, да и мне иметь дело с
ними не приходилось.
Единственное, что может быть актуально для пользователя десктопа --
это внешние диски с интерфейсом FireWire. Однако я таковых не только
не пользовал, но и не видел, и потому ничего за них не скажу. Могу
только предположить, что и они предстанут в каталоге /dev в качестве
SCSI-дисков -- если кто поделится сведениями по сему поводу, буду
признателен.
Далее в этом разделе речь пойдет исключительно о жестких дисках,
сиречь винчестерах. Как известно, диски принято делить на разделы
(partitions в терминах DOS/Windows и Linux). Но FreeBSD и тут
отличается оригинальным подходом. Чтобы понять его, нужно для начала
сказать
Немного о "геометрии"
Слово "геометрия" в заголовке рубрики взято в кавычки не случайно.
Дело в том, что с тех пор, как объем дисков перевалил за 500 с
небольшим мегабайт (ограничение старых BIOS персональных, ранее
именовавшихся IBM-совместимыми, компьютеров), с реальной их геометрией
пользователь никогда не сталкивается. Софт, прошитый в дисковой
электронике (т.н. firmware) преобразует ее к виду, доступному
восприятию BIOS -- на деталях, как именно это делается,
останавливаться не буду за некомпетентностью (да и вряд ли кто, кроме
производителей дисков, эти детали знает хорошо).
А доступная BIOS геометрия диска описывается в терминах
цилиндр/головка/сектор (cylinders/heads/sectors, C/H/S). Фигурально
говоря, головки считывают информацию с концентрических магнитных
дорожек (tracks), на которые поделена каждая дисковая пластина.
Вертикальная совокупность треков с одинаковыми номерами на всех
пластинах, составляющих диск как физическое устройство, и образует
цилиндр. А сектора нарезают пластину, вместе с ее треками, на
радиальные фрагменты, именуемые блоками. То есть это можно представить
себе таким образом, что блок лежит на пересечении (в пространстве)
цилиндра, трека и сектора. Число треков и секторов в современных
дисках обычно фиксировано (вернее, предстает таковым в BIOS): 255
треков нарезается на 63 сектора каждый, что в совокупности дает 16065
блоков на цилиндр. А количество цилиндров определяется объемом диска
(в арифметические вычисления вдаваться не буду). Важно здесь только
то, что головки диска механически двигаются синхронно по поверхности
всех пластин. То есть если на одной пластине информация считывается с
1-го трека, то и все прочие головки перемещаются на ту же дорожку --
каждая на своей пластине.
Повторяю, все это условно -- хотя бы потому, что понятие цилиндра в
геометрическом смысле слова очень трудно применить к современным
дискам, часто не то что однопластинным, а даже, если так можно
выразиться, полупластинным (то есть только с одной задействованной
стороной единственной пластины). Но разбираться с этой геометрией --
дело firmware и BIOS, для нас же интересны именно цилиндры --
совокупность треков, к которым осуществляется синхронный доступ, и
блоки -- минимальные кванты дискового пространства.
Образующие цилиндры треки создаются при первичной заводской разметке
диска -- т.н. низкоуровневом форматировании. Из сказанного выше
очевидно, что доступ к данным в пределах одного цилиндра или группы
соседних будет выполнен быстрее, чем к данным, записанным частично на
первый и, скажем, на последний цилиндр диска. Этот случай не столь уж
невероятен, как может показаться: в DOS'е, где пространство, занятое
стертыми файлами, помечается как неиспользуемое, но реально
перезаписывается только тогда, когда по настоящему свободное место на
диске вообще исчерпано, такая ситуация вполне могла бы возникнуть.
Так вот, чтобы свести к минимуму вероятность разнесения данных по
разобщенным цилиндрам, и придуманы были дисковые разделы (вернее, в
том числе и для этого -- выделение дисковых разделов преследует
множество других целей). В единый раздел объединяется группа смежных
цилиндров. Где кончается один раздел и начинается другой? Резонные
люди из Одессы сказали бы, что полиция кончается именно там, где
начинается Беня Крик. Однако для нас очевидно, что для каждого из
разделов следует хранить сведения о его начале и конце (то есть номера
1-го и последнего из задействованных в нем цилиндров). Где их хранить?
Для ответа на этот вопрос следует обратиться к понятию блока.
Как и треки, дисковые блоки (или физические -- есть еще блоки
логические, но это относится уже к файловым системам) создаются при
низкоуровневом форматировании, и пользователь влиять на них (почти) не
может. Размер их также всегда одинаков и равен 512 байтам. Вернее,
таким он видится BIOS'у персоналки -- каков он на самом деле, одному
Аллаху ведомо. Однако то, что обмен данными с диском возможен минимум
512-байтными порциями -- объективная реальность, как и то, что любой,
сколь угодно маленький, объем информации, записанный на него, будет
занимать целый блок. С другой стороны, считывание данных блоками по
512 байт будет происходить быстрее, чем если бы при каждом обращении
головки к диску данные считывались бы побайтно. Однако и это относится
уже к теме файловых систем.
А пока нам интересен один-единственный блок, образованный первым
сектором на первом треке первого цилиндра. Он резервируется под
служебную область диска, именуемую главной загрузочной записью (MBR --
Master Boot Recodr), которая и считывается BIOS'ом при старте машины.
Очевидно, что по прямому назначению MBR используется только в том
случае, если диск определен в Setup'е BIOS'а как загрузочный (или
просто является единственным в системе). Однако поскольку
использование каждого конкретного диска остается на усмотрение
пользователя, место под него отводится всегда.
Внутри нулевого блока, помимо прочего (в частности, кода какого-либо
начального загрузчика, который может быть туда записан) есть еще один
зарезервированный участок. Он предназначен для BIOS'овской таблицы
разделов (Partition Table), под которую испокон веков отведено 64
байта. В эту таблицу записываются (или могут быть записаны) данные о
разделе (разделах) в определенном, доступном пониманию BIOS'а,
формате. А формат этот предусматривает указание стартового блока,
размера в байтах, идентификатора типа файловой системы и (только для
одного из разделов) флага активности (то есть помечающего данный
раздел как загрузочный). Последнее необходимо для некоторых
операционок типа DOS, хотя FreeBSD или, например, Linux'у флаг этот
глубоко безразличен.
Всего информации, необходимой для описания дискового раздела, набегает
16 байт. А поскольку, как мы помним, под всю таблицу разделов этих
байт отведено лишь 64, без калькулятора можно подсчитать, что
предельное количество разделов на диске -- 4. Эти разделы называются
первичными или, не совсем точно, физическими. Так как в большинстве
случаев такие разделы могут быть также поделены на части -- разделы
логические (о чем речь впереди).
Повторю еще раз -- это относится только к машинам с PC BIOS, то есть
обычным персоналкам. На всякого рода PowerPC, Sparc'ах и тому подобных
станциях все может быть совсем по другому (хотя как именно -- честно
говоря, не Ганнибал, не знаю).
Как можно заметить, в описание раздела входит идентификатор файловой
системы. Это -- некоторое число (во FreeBSD обычно в десятичном
представлении, в Linux'е, например, -- в шестнадцатеричном), которое
ставится в соответствие с файловой системой операционки, планируемой к
размещению на диске. Так, раздел, предназначенный для FreeBSD, имеет
идентификатор 165 (десятичный) или A5, раздел для Linux (Linux native)
-- 131 (или 83), FAT16 -- 6, расширенный раздел (т.н. DOS Extended) --
5, и так далее.
Присвоение разделу какого-либо идентификатора не значит, что тем самым
на нем волшебным образом возникает соответствующая файловая система.
Нет, он просто предопределяет, какого рода вторичная таблица разделов
может быть на нем записана. Но тут мы переходим к разговору
Собственно о слайсах
Итак, следствием установлено, что на одном физическом диске может быть
создано до 4 (включительно) разделов, каждый их которых может быть
приписан к отдельной операционной системе. А что дальше? А дальше
следует изучить вопрос стилей разметки разделов.
Стили разметки разделов именуются Disk Label, что не следует путать с
метками дисков (disk label) -- произвольными именами, которые в DOS (и
не только) можно присвоить дисковому разделу. Стили же разметки -- это
формат вторичной таблицы разделов, записываемой в первый блок раздела
первичного. Эта таблица и определяет характер доступных действий над
данным первичным разделом.
Пользователи Windows (да в большинстве случаев и Linux) обычно не
имеют причин задумываться над проблемой стилей разметки. Однако стилей
таких существует немало -- чтобы убедиться в этом, достаточно зайти в
меню конфигурации ядра Linux, в подраздел Partition Types раздела File
systems. Однако из всего этого изобилия нас будут интересовать только
два стиля -- DOS и BSD.
В DOS/Windows используется DOS-стиль разметки разделов. Он
основывается на BIOS-таблице, задействованной лишь частично. А именно
-- из четырех доступных записей Partitions Table заполняются только
две (вернее, только два раздела можно создать средствами стандартного
FDISK из DOS/Windows; как обстоит дело в NT/2000/XP -- просто не
знаю). В записи для первого раздела можно указать идентификатор типа
файловой системы (например, FAT16 или FAT32), второму же разделу
автоматически присваивается идентификатор типа Extended DOS. А уж
Extended-раздел может быть далее поделен на логические разделы.
Впрочем, это не интересно, да и многократно описывалось.
В Linux также используется DOS-стиль разметки. Только тут уж
BIOS-таблица задействуется по полной программе -- стандартными
средствами можно создать все четыре первичных раздела и пользовать их
в свое удовольствие. Правда, опять же лишь один из них можно объявить
расширенным и, соответственно, поделить на разделы логические.
Совершенно иначе выглядит BSD-стиль разметки (BSD Label), используемый
во FreeBSD, Net- и OpenBSD и в BSDi. Здесь также может быть
использована BIOS-таблица, заполнение которой создаст четыре первичных
раздела. В терминологии FreeBSD они именуются слайсами (slices --
наиболее точным переводом будет <<отрезки>>), чтобы отличать их от
партиций (partitions) BSD-разметки. Слайсы в номенклатуре файлов
устройств маркируются добавлением к имени файла диска литеры s и
порядкового номера (в отличие от дисков, начиная с единицы), например:
ad0s1, ad0s2, ad0s3, ad0s4 для мастер-диска на первом IDE-канале.
Если одному или нескольким из слайсов будет присвоен идентификатор
BSD-системы -- 165 в десятичном исчислении (строго говоря, он
называется 4.2BSD и свойственен также NetBSD), то в его начальный блок
запишется собственно BSD-таблица разделов (BSD Label). В соответствие
с ее форматом, каждый слайс с ID 165 абсолютно равноправен и может
быть поделен на логические разделы (собственно partitions, в
терминологии FreeBSD). Для партиций в BSD-таблице предусмотрено восемь
записей. Соответствующие им разделы номенклатурно маркируются
добавлением к имени файла слайса литеры -- от a до h. То есть таких
логических разделов, казалось бы, может быть создано восемь. Однако
практически это не совсем так (вернее, совсем не так).
Начать с того, что одна из записей (третья по счету, маркируемая
литерой c) резервируется для описания всего слайса в целом -- ad0s1c,
необходимость чего станет ясной в дальнейшем. Далее, первая запись
таблицы, соответствующий которому файл устройства маркируется как
ad0s1a, отводится для описания корневого раздела файловой системы. А
очевидно, что на конкретной локальной машине корневой раздел может
быть только один, вне зависимости от количества дисковых разделов и
даже физических дисков. И наконец, вторая запись (файл устройства --
ad0s1b) предназначена для описания раздела подкачки (swap-раздела),
который, во-первых, не может содержать данные, и во-вторых, является
единственным на весь диск (ясно, что создавать по свап-разделу в
каждом слайсе бессмысленно, хотя при наличии двух физических дисков
поделить между ними пространство подкачки -- идея вполне здоровая). В
итоге на четырех слайсах физического диска может быть создано 22
раздела -- 1 корневой, один раздел подкачки и 20 разделов для хранения
данных.
Практически, однако, так никто, насколько я знаю, не делает. Создание
слайсов преследует своей целью разместить на диске более чем одну
операционку и сохранить возможность обмена данными между ними
(теоретически к BSD-разделам можно обращаться из Linux'а, если
пересобрать его ядро должным образом; хотя обратная процедура --
обращение к ext2fs разделу из FreeBSD, -- гораздо проще).
Если же весь наличествующий диск планируется отдать на растерзание
FreeBSD, то проще создать один-единственный слайс на (почти) весь его
объем, оставив записи в BIOS-таблице для остальных неиспользованными.
Ну а семи позиций BSD-таблицы обычно более чем достаточно для
обособления всех необходимых ветвей файловой системы, таких, как /usr,
/tmp, /var и /home. Впрочем, к вопросу построения оптимального древа
файловой системы мы еще вернемся в следующих заметках.
Разметка диска, использующая записи в BIOS-таблице первого блока,
называется разметкой в режим совместимости. Вне зависимости от того,
создается ли один слайс для FreeBSD или несколько отдельных -- для
каждой операционки, в режиме совместимости в начале диска
резервируется пространство в размере 63 блоков (всего около 30 Кбайт),
в котором не только сохраняется в неприкосновенности <<умолчальный>>
MBR, но и остается место для записи кода какого-либо стороннего
загрузчика. В итоге диск остается доступным для других операционных
систем, по крайней мере теоретически.
Однако использование режима совместимости и BIOS-таблицы разделов во
FreeBSD не является обязательным. Вполне допустимо записать в MBR,
вместо таблицы BIOS, непосредственно BSD-таблицу разделов. В этом
случае понятно, что слайсов как таковых не создается, а все дисковое
пространство представляет собой как бы единый слайс, и может быть
разбито на BSD-партиции по тем же правилам, что и отдельный слайс. И
тут становится ясной необходимость резервирования третьего поля
BSD-таблицы -- именно в ней и описывается весь наш диск.
Такое обращение с диском именуется режимом эксклюзивного использования
или Dangerously Dedicated. Вопреки названию, в нем не таится никакой
опасности ни для данных пользователя, ни для его здоровья. А
единственная подстерегающая его опасность -- это то, что диск в
эксклюзивном режиме не будет опознан никакой другой операционной
системой, установленной на данном компьютере (обращению к диску по
сети он препятствий не составит). Однако это -- чисто теоретическое
неудобство, потому что ни одна из известных мне операционок все равно
не умеет толком работать с BSD-разделами и файловой системой FreeBSD
(особенно современной -- UFS2). А, скажем, при наличии на другом
физическом диске мультизагрузчика GRUB, FreeBSD с <<эксклюзивного>>
диска вполне может быть им загружена. Опять же, если не используется
UFS2, этой файловой системы текущая версия GRUB'а не знает, а
организовать цепочечную загрузку a la Windows для <<эксклюзивного>>
диска, вероятно, не удастся (впрочем, не проверял, исхожу из общих
соображений).
В документации по FreeBSD встречаются указания, что <<эксклюзивные>>
диски иногда не могут быть загрузочными, вероятно, потому, что BIOS не
сможет опознать нестандартные записи в MBR. Однако, видимо, это
относится к каким-либо старым версиям BIOS -- мне с таким сталкиваться
не приходилось, хотя я всегда прибегаю к эксклюзивному режиму при
возможности отдать под FreeBSD целый физический диск.
Номенклатурное заключение
В заключение суммируем все, что ранее было сказано о номенклатуре
накопителей, слайсов и BSD-партиций, в виде простенькой таблицы:
Дивайс Назначение
ad0 Master-диск на 1-м IDE-канале
ad0s1 Первый слайс на нем (в режиме совместимости)
ad0s1a Корневой раздел первого слайса
ad0s1b Раздел подкачки
ad0s1с Unused, предназначен для описания слайса в целом (как и ad0s1)
ad0s1d
... Разделы для отдельных ветвей файловой системы
ad0s1h
ad0a Корневой раздел Master-диска (в эксклюзивном режиме)
ad0b Раздел подкачки на нем
ad0c Unused, описывает весь <<эксклюзивный>> диск
ad0d
... Разделы для отдельных ветвей файловой системы
ad0h
Для диска, подсоединенного к контроллеру IDE-RAID, файлы разделов
будут иметь вид ar0s1a -- ar0s1h. Zip-диску из коробки,
отформатированному фабричным способом, будет соответствовать файл вида
ad2s4 (в случае подключения Master'ом на 2-й канал). Фабрично же
размеченная флэшка будет выглядеть вроде da0s4 (как точно -- забыл, а
под рукой фабрично размеченной нет, проверить не могу).
Особым образом будут выглядеть разделы, объединенные в программный
RAID-массив. Однако к этому мы вернемся после практических упражнений
по просмотру и созданию слайсов и партиций.
FreeBSD: практика дискодробительства
При начальной установке FreeBSD для создания слайсов и разделов на них
обычно используется программа sysinstall -- универсальный установщик и
настройщик этой операционки. Однако следует помнить, что это -- не
более чем front-end к серии специализированных утилит, в том числе и
утилит дисковой разметки. И потому знакомство с ними будет не вредным
в любом случае. С одной стороны, оно даст понимание того, что же
все-таки делает sysinstall. С другой -- некоторые действия по
разбиению диска с их помощью оказывается выполнить проще. Так, я
затратил в sysinstall немало времени на создание разделов для
подготовки программных RAID-массивов, пока не понял, что сделать это
вручную -- гораздо легче.
Есть и третья сторона -- утилиты дисковой разметки, помимо выполнения
своей прямой функции, служат незаменимым источником информации о
физическом диске вообще и о том, что по его поводу думает FreeBSD. И
потом -- с их помощью можно получить такие сведения о дисковых
разделах, каких не найти больше нигде.
Разметка слайсов
В отличие от Linux'а, разбиение диска во FreeBSD осуществляется в два
этапа и двумя отдельными программами. Сначала диск нарезается на
слайсы (или создается один слайс, в режиме ли совместимости, или для
эксклюзивного использования). А затем уже слайс, отведенный для
FreeBSD, разбивается на партиции.
Выполнению первой задачи служит утилита fdisk. Это -- еще более мощное
средство работы с дисками, чем одноименная программа из Linux'а.
Однако ее нельзя назвать легкой в использовании. Даже в man (8) fdisk
среди BUG'ов отмечено, что интерфейс ее мог бы быть и подружественней.
Однако на самом деле пользоваться ей совсем не страшно.
Запущенная без опций и аргументов, команда fdisk просто выдает
информацию о первом физическом диске машины (вернее, о том диске, на
котором размещается корневая файловая система FreeBSD). И информацию
богатую: здесь мы увидим и имя файла текущего дискового устройства
(например, /dev/ad0), и сведения о его геометрии (количество
цилиндров, головок, секторов на трек, блоков на цилиндр -- другое
дело, что к реальной геометрии они отношения не имеют, но об этом мы
уже говорили), и размер физического блока.
А дальше последует информация о слайсе или слайсах, на этом диске
проживающих. И тут для каждого слайса мы увидим идентификатор типа
файловой системы, его размер (в блоках и мегабайтах), флаг активности
(если таковой имеет место быть), данные о начале и конце (номер
цилиндра/головки/сектора). Если на диске существует менее четырех
слайсов, несуществующие (то есть соответствующие незаполненным записям
таблицы разделов) будут помечены как UNUSED. Та же пометка будет на
слайсах 2-4 при диске, размеченном в эксклюзивном режиме.
Тем не менее, даже при единственном слайсе на диске, размеченном в
режиме совместимости, отличить его от <<эксклюзивного>> диска по
выводу команды fdisk очень легко: стартовый блок первого будет 63, и
начальный трек его будет носить первый номер. Тогда как слайс
<<эксклюзивного>> диска будет начинаться с нулевого блока и нулевого
же трека.
Как уже сказано, вся эта информация относится к диску с корневой
файловой системой. Чтобы получить аналогичные сведения о других
накопителях, имя файла соответствующего устройства нужно указать в
явном виде в качестве аргумента команды 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 сектора. Очевидно, что если
диск перед этим был как-то разбит и содержал какие-либо данные, и
разметка диска, и его содержимое будут безвозвратно уничтожены.
Впрочем, такое поведение типично для всех утилит дисковой разметки в
любой ОС. Правда, тут нас даже не спросят о подтверждении своих
действий, так что следует быть внимательным.
Зато много вопросов последует при использовании опции -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. А вот если факт <<плохой>>
геометрии имеет место быть -- стоит задуматься.
Я с такой ситуацией столкнулся на примере двух идентичных дисков --
Seagate Barracuda IV объемом 80 Гбайт, которые показали абсолютно
разную геометрию, причем один -- количество цилиндров, треков и
секторов, не имеющее ничего общего с реальностью. В результате на
дисках оказалось не только разное количество блоков на цилиндр, но и
объем их различался на 3 Мбайта (мелочь, а неприятно).
И я принял решение исправить ситуацию руками. Для чего сначала ответил
положительно на указанный выше вопрос, после чего мне было предложено
ввести последовательно все указанные параметры. Что я проделал, указав
правильные, на мой взгляд, значения числа цилиндров, треков и
секторов. Подтверждение правомерности этих действий было получено
позднее -- при сверке с таковыми из sysinstall (а эта программа
разрешает подобные коллизии автоматически). В итоге диски уравнялись в
объеме, и я продолжил свои развлечения с ними.
А первейшее развлечение после исправления геометрии (или вместо нее) в
команде
$ fdisk -i /dev/ar0
- это ручное создание слайсов (при существующей уже разметке сначала
будет вопрошаемо, а хотим ли мы этого -- с отрицательным ответом по
умолчанию). Для этого сначала запрашивается идентификатор типа
файловой системы (по умолчанию стоит существующий, если диск был
размечен, или 0 -- для диска нового) -- следует указать его десятичное
значение (165 для FreeBSD-слайса). Затем -- стартовый сектор (0 -- при
<<эксклюзивной>> разметке, 63 -- при разметке в режиме совместимости),
и размер слайса в блоках (при использовании всего диска, очевидно, он
будет равен полному их числу, в противном случае -- потребуются
некоторые арифметические вычисления).
После этого будет предложено точно специфицировать начало и конец
слайса. Если отказаться -- они будут взяты из предыдущих определений,
если согласиться -- нужно будет указать первые и последние цилиндр,
головку, сектор. Каковые и будут выведены в виде
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:
<UNUSED>
Do you want to change it? [n]
- по той же схеме, что и первого. Ясно, что если создается всего один
слайс, следует отказаться от изменений остальных потенциальных записей
таблицы разделов -- в этом случае они останутся помеченными как
неиспользуемые. В любом случае будет задан последний вопрос --
подтверждение на выполнение:
Do you want to change the active partition? [n]
При положительном ответе на который все сделанные изменения вступят в
силу (и на ранее размеченном диске можно будет распроститься с его
содержимым). Так что следует предварительно просмотреть все ранее
введенное (благо, во FreeBSD это легко сделать пролистыванием буфера
истории виртуальной консоли) и при обнаружении ошибки отказаться от
изменений и запустить команду fdisk по новой. Впрочем, из нее можно в
любой момент выйти без последствий и стандартным образом --
комбинацией клавиш Control+C.
В общем, интерактивное создание с помощью fdisk единственного
<<эксклюзивного>> слайса (а единственный <<совместимый>> слайс проще
создать с помощью опции -I) не так уж и страшно. Если же слайсов
потребуется несколько -- придется вооружиться калькулятором (во
FreeBSD есть такой -- 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 слайс, вне зависимости от того,
<<эксклюзивный>> он или совместимый, еще не пригоден к установке на
него FreeBSD (или какому-либо иному использованию). Предварительно его
еще нужно разбить на партиции (или хотя бы создать одну партицию,
ad#s1c, описывающую слайс целиком). Ранее этой цели служила утилита
disklabel, однако в версии 5.1 она заменена на заимствованную из
NetBSD программу bsdlabel (с более дружественным, как говорят
оптимисты, интерфейсом). Хотя и disklabel можно обнаружить в каталоге
/sbin, но это -- лишь жесткая ссылка на ту же бинарную программу.
Опять же, запущенная без опций (однако с обязательным аргументом в
виде имени устройства), bsdlabel служит исключительно целям
информирования о положении вещей, выводя для размеченного под FreeBSD
слайса нечто вроде следующего:
$ bsdlabel /dev/ad0
# /dev/ad0:
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), тип файловой
системы и ее параметры: размер фрагмента, блока, плотность записей --
обо всем этом пойдет речь в заметке про файловую систему FreeBSD; пока
же необходимо отметить, что блок файловой системы -- логический, и это
совсем не то же самое, что физический блок диска. Не будем пока
обращать внимание и на то, что в соответствующих колонках для всех
партиций, кроме a, стоят нули.
Среди партиций обращает на себя внимание помеченная литерой c: это тот
самый <<контейнер>> для остальных разделов (дальняя аналогия --
extended partition DOS). Ясно, что оффсет для него -- нулевой
(приведенный пример относится к <<эксклюзивному>> диску, в режиме
совместимости в этом поле стояло бы 63), а размер равен полному
количеству физических блоков диска. Для прочих партиций смещение легко
(с помощью калькулятора 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
Если на этом слайсе не планируется размещать корневую файловую
систему, для создания единственной партиции достаточно будет дописать
(самыми обычными редакторскими средствами) строку вида
d: 254787 0 4.2BSD
И -- выйти из редактора его штатной командой с сохранением изменений
(в случае с vi -- :wq), в ответ на что мы будем проинформированы, что
File /tmp/EdDk.KvEGsqRNsh saved.
И при следующем вызове bsdlabel для того же слайса, но без опций
картина окажется следующей:
# /dev/da0:
8 partitions:
# size offset fstype [fsize bsize bps/cpg]
c: 254787 0 unused 0 0 # <<raw>> part, don't edit
d: 254787 0 4.2BSD 0 0 0
То есть можно видеть, что <<рабочая>> партиция успешно создана.
Для создания нескольких партиций, в том числе корневой и для swap'а
нам опять же потребуется некоторая арифметика, аналогичная примененной
в интерактивном режиме программы fdisk. То есть каждый раздел, начиная
с a, должен получить значение начального оффсета (первый --
соответствующий начальному блоку всего слайса, остальные -- сумме
оффсета и размера предыдущего), размера (опять же в блоках), типа
файловой системы (для <<рабочих>> партиций -- 4.2BSD, для раздела
подкачки -- swap).Поля параметров файловой системы можно не заполнять
-- в этом случае они примут некие <<умолчальные>> значения,
рассчитываемые, как я понял, исходя из объема партиции. А можно
проставить в них нули -- в таком случае параметры файловой системы
будут определяться только при ее создании (то есть <<форматировании>>,
в терминах DOS, раздела).
На этом вопрос слайсов и партиций в первом приближении можно считать
закрытым. Конечно, созданные партиции все еще не пригодны к
использованию -- предварительно на них нужно создать файловые системы.
Или, как выражаются <<подоконники>>, отформатировать их. Чем мы и
займемся в самое ближайшее время...
Алексей Федорчук (alv@linux-online.ru, UNIX4all - http://linuxshop.ru/unix4all)
Опубликовано -- 18 января 2004 г.
FreeBSD: физика файловой системы
Вступление незапланированное
Он пришел с лицом убийцы,
С видом злого кровопийцы,
И сказал, что он мой критик,
И добра желатель мой.
Что ему, мол, стиль мой низкий
Эстетически не близкий.
Я фуфло, а он Белинский,
Весь неистовый такой.
Тимур Шаов,
Разговор с критиком
К сочинению настоящего вступления меня побудило большое количество
откликов на первые три статьи этого цикла. Которые можно разделить на
положительные и критические. Вот я и решил ответить на все, так
сказать, оптом.
С откликами первой группы все понятно: могу только поблагодарить за
поддержку. Конечно, все свои сочинения писались в первую очередь ради
собственного удовольствия, однако приятно, что еще кому-то интересно
их читать.
На голословную критику я ответил бы так: уважаемые господа, если вы
полагаете, что разбираетесь в рассматриваемых вопросах лучше меня (во
что я готов охотно поверить), почему бы вам не уделить толику времени,
проводимого в форумных флеймах, просвещению широких народных масс? И
не сочинять бы то, что нужно, и так, как нужно, на соответствующие
темы? Желательно -- русским литературным языком, с минимумом
идио-мат-тических выражений. Я же с удовольствием возьму на себя роль
внимательного читателя, впитывая всю представленную вами полезную
информацию. И критика -- с позиций русского литературного языка
(интуиция мне посказывает, что поводов для оной будет более чем
достаточно).
Тем не менее, должен добавить, что очень признателен за всю критику
конструктивного характера. На которую надеюсь и впредь.
Просто вступление
В настоящей заметке речь пойдет о способе физической организации
блоков дискового раздела, обеспечивающем возможность записи, хранения
и манипулирования файлами, специфичном для FreBSD вообще и 5-й ее
ветки в особенности.
Файловая система FreeBSD принадлежит к Unix-семейству файловых систем
и обладает множеством общих для всех них черт. Она носит название UFS,
в 5-й ветке используется ее усовершенствованная разновидность -- UFS2.
Для начала рассмотрим общие принципы устройства той и другой, а потом
обратимся к рассмотрению особенностей, свойственных UFS2.
Для файловой системы FreeBSD (и вообще BSD-систем, начиная с 4.2BSD)
можно встретить и еще одно наименование -- FFS (Fast File System,
обозначение <<быстрая>> введено в сравнении с файловой системой Unix
System V -- s5). В доступной литературе мне не удалось обнаружить
четкой формулировки их взаимоотношения. У меня сложилось впечатление,
что FFS -- это родовое обозначение файловых систем всех операционок
BSD-клана (Free-, Net-, OpenBSD и BSDi), тогда как UFS (и UFS2) -- имя
конкретной реализации для FreeBSD. Хотя и в NetBSD ныне (начиная с
версии 1.6 и выше) наряду с традиционной FFS может использоваться
UFS2. В общем, однозначно осветить этот вопрос затрудняюсь, и потому
был бы признателен за разъяснение.
Как уже было [29]выяснено ранее, дисковая партиция -- это, говоря
метафорически, группа смежных цилиндров, разбитых на физические блоки
по 512 байт. Партиция, несущая на себе файловую систему UFS,
разделяется на три самостоятельные области (от начала группы цилиндров
к ее концу) -- суперблок, индексную таблицу и область данных.
Рассмотрение их целесообразно начать с конца списка, то есть с области
данных.
Блоки данных
Область данных (она занимает подавляющий объем пространства партиции)
образована блоками файловой системы. Подобно физическому блоку, блок
файловой системы (именуемый также блоком логическим) представляет
собой квант информации, доступный за одну операцию чтения/записи, но
уже не дисковой головки, а операционной системы. Очевидно, что
логический блок не может быть меньше физического (то есть 512 байт), и
размер его обязательно кратен целому числу последних.
Понятие логического блока введено для повышения производительности
дисковых операций. Не требует доказательства утверждение, что скорость
обмена данными квантами по 1 Кбайт будет выше, чем 512-байтными,
2-килобайтными -- еще быстрее, и так далее. И потому с точки зрения
быстродействия файловых операций выгоден максимальный размер
логического блока файловой системы.
С другой стороны, увеличение размера логического блока ведет к
непроизводительному расходу дискового пространства за счет т.н.
внутренней фрагментации данных. Ее не следует путать с внешней
фрагментацией, для борьбы с которой на файловых системах FAT-семейства
были в свое время мобилизованы всякого рода speeddisk'и с
комбатантами: вследствие особенностей алгоритмов управления данными
файловые системы Unix-семейства настолько мало подвержены внешней
фрагментации, что о преодолении оной вообще практически не говорят.
Внутренняя же фрагментация выражается в том, что данные файлов, размер
которых меньше блока файловой системы, все равно занимают его целиком.
Также целый блок потребуется и для хранения файловых хвостов, то есть
остатков сверх объема, кратного размеру логического блока. Для борьбы
с фрагментацией в UFS, пардон за тавтологию, введено понятие фрагмента
-- логической части блока файловой системы, которая может быть
записана или считана независимо от остальной его части.
Ясно, что размер фрагмента все равно не может быть меньше физического
блока. При этом UFS накладывает на него и встречное ограничение --
минимальный размер фрагмента определяется в 1/8 логического блока.
Другие же возможные значения -- 1/4 и 1/2 блока файловой системы
(очевидно, что выделение фрагмента в размере блока равносильно отказу
от фрагментации блока вообще, хотя это, как будто бы, не запрещено).
Inodes
Каким образом определяется принадлежность блока данных тому или иному
файлу? К помощью индексной таблицы, именуемой также таблицей файловых
дескрипторов или таблицей inodes. Она образована некоторым (конечным)
количеством записей фиксированной длины (128 Кбайт в UFS, 256 -- в
UFS2), каждая из которых однозначно соответствует одному файлу, как
реально существующему, так и только могущему быть созданным.
Такая запись индексной таблицы носит название inode, которое мы и
оставим за нею. Ибо все известные мне переводы этого термина, вроде
информационных узлов или индексных дескрипторов, выглядят очень
коряво. Кроме того, слово <<дескриптор>> фигурирует еще и в контексте
<<дескриптор файла>>, под чем подразумевается идентификатор
(уникальный, иначе что же он будет идентифицировать?) файла,
используемого неким процессом (что уже к файловым системам не имеет ни
малейшего отношения -- это сфера подсистемы управления процессами). И
эти дескрипторы -- не имеют меж собой ничего общего. Так, inode c
идентификатором 2 (а это всегда идентификатор корневого каталога
файловой системы) и дескриптор файла с номером 2 (а им для любого
процесса будет стандартное устройство вывода сообщений об ошибках,
/dev/stderr) ни коим образом друг с другом не соотносятся (хотя об
этом почему-то не любят говорить вслух).
Однако я отвлекся -- вернемся к нашим inodes. Каждый член этой таблицы
содержит так называемые метаданные файла. Для реально существующего
файла они включают в себя:
* уникальный идентификатор inode (и, соответственно, файла,
метаданные которого он содержит) -- это просто счетчик создаваемых
файлов в файловой системе);
* тип файла -- это может быть каталог, символическая ссылка, файл
устройства, именованный канал или сокет, или же обычный (то есть
не относящийся ни к какому из перечисленных типов) файл;
* размер файла в байтах;
* количество ссылок на файл (к этому вопросу придется вернуться чуть
ниже);
* адреса логических блоков и их фрагментов, составляющих файл;
* число занятых им блоков;
* атрибуты файла -- принадлежности, доступа, времени (и это еще не
раз будет предметом подробного рассмотрения).
А вот чего в inode не обнаружить никакими силами -- так это имени
соответствующего ему (или ей? -- мне почем-то кажется, что inode,
вопреки грамматике, -- женского рода). В любой книжке про Unix не
устают повторять (и я не отступлю от этой традиции), что имя файла --
атрибут не самого файла, а каталога, в который он входит. Поскольку
понимание этого потребуется при знакомстве с механизмом Soft Updates в
следующей заметке, сделаю маленькое отступление для прояснения вопроса
именования файлов во FreeBSD (и вообще в Unix).
При описании содержания таблицы inodes вскользь было упомянуто поле
типа файла. Так вот, в Unix все файлы (а все, что в Unix имеется
вообще, включая физические устройства, для системы представляется в
виде файлов) делятся на две группы -- каталоги и прочие. Прочие файлы
могут служить для различных целей (хранения данных и исполняемых
программ, быть символическими ссылками, описывать устройства или
средства взаимодействия процессов -- обо всем этом мы поговорим
своевременно или несколько позже). Назначение же каталогов --
единственное, но оченно важное: быть хранителями имен входящих в них
файлов, которым однозначно поставлены в соответствие идентификаторы
inodes, хранящих метаданные этих файлов.
То есть имя файла существует только в списке каталога и нигде более в
системе. А создание файла -- это не только заполнение относящейся к
нему записи в индексной таблице и заполнение указанных в ней блоков
данных, но и внесение записи вида <<идентификатор -- имя_файла>> в
область данных какого-либо каталога. А каталог, как и любые другие
файлы, имеет свои метаданные в таблице inodes и свою область данных.
И, в свою очередь, имя его вместе с идентификатором inode входит в
каталог более высокого уровня, и так -- вплоть до корня файловой
системы. В поле количества ссылок inode создаваемого файла
устанавливается минимально возможное значение, равное единице,
поскольку любой файл входит по меньшей мере в один каталог, иначе он
просто не будет доступен системе -- файлы с нулевым количеством ссылок
для нее как бы не существуют (и на самом деле их inodes и блоки данных
со временем неизбежно будут перезаписаны физически).
На самом деле один и тот же набор данных и метаданных может быть
приписан к произвольному количеству каталогов в пределах одной
файловой системы и даже фигурировать под разными именами в одном
каталоге -- в этом случае количество ссылок на него будет
соответствующим. А вот минимальное количество ссылок на каталог равно
двум -- так как запись о нем существует как в родительском каталоге
(..), так и в текущем (. -- то есть в самом себе). И каждый вложенный
подкаталог увеличивает счетчик ссылок каталога на единицу.
Ссылки, с помощью которых связывается имя файла как элемент каталога с
его записью в таблице inodes и блоками образующих файл данных,
именуются еще жесткими (hardlinks, хорошим русскоязычным эквивалентом
было бы слово <<связь>>, но оно как-то не прижилось). Посредством
жестких ссылок одному и тому же набору данных или исполняемой
программе можно придать произвольное количество имен, которые никто не
запрещает включить в один и тот же или разные каталоги. Единственное
условие для этого -- все эти имена-дублеры должны находиться в
каталогах единой файловой системы, то есть располагаться на одной
дисковой партиции. И в одной из последующих заметок станет ясно,
почему.
Забегая несколько вперед, отмечу, что жесткие ссылки нужно отличать от
ссылок символических (symlinks, часто говорят просто links -- почему и
резонно было бы сохранит за ними обозначение ссылок, а hardlinks по
русски именовать связями). Символические ссылки -- файлы особого типа,
отдаленно сходные с ярлыками в Windows или shadow в OS/2, которые сами
по себе никаких данных не содержат, а просто ссылаются на метаданные и
данные другого файла (который может локализоваться и за пределами
данной файловой системы).
Для файлов несуществующих свободные записи в таблице inodes просто
резервируются. А поскольку количество этих записей -- конечно, именно
объем индексной таблицы и определяет, сколько файлов реально может
быть создано в данной файловой системе. Исчерпание свободных записей в
ней приводит к тому, что, вне зависимости от объема свободного
дискового пространства, ни одного нового файла создать не удастся.
Суперблок
Однако сведений об объеме индексной таблицы внутри нее не
обнаруживается. Ибо место их размещения -- тот самый суперблок,
который идет первым в нашей партиции (вообще-то первым в любой
партиции будет загрузочный блок, но реально он занят только в
загрузочном же разделе -- во всех остальных для него просто
зарезервировано место). Кроме этого, в суперблоке же записывается
размер блока файловой системы и их суммарное количество, число блоков
данных, размер блокового фрагмента и их число в блоке, число блоков,
реально занятых файлами, объем партиции, перманентно резервируемый как
свободный, и еще множество характеристик файловой системы, о которых
сейчас говорить неуместно.
На самом деле описанное выше несколько упрощено. Специфика файловых
систем BSD-клана заключается в том, что реально дисковая партиция
разбивается на части фиксированного объема (зависящего от объема
раздела). Это т.н. группы цилиндров, каждая из которых имеет свою
копию суперблока (чем обеспечивается устойчивость к механическим
повреждениям диска), свой блок группы цилиндров, оную описывающий (в
нем, в частности, содержатся карты свободных/занятых inodes и карты
свободных/занятых блоков данных), собственную таблицу inodes и область
блоков данных. Это имеет целью размещение inodes и относящихся к ним
блоков данных максимально близко друг к другу, что, кроме повышения
производительности, влечет за собой и сведение к минимуму той самой
внешней фрагментации данных, о которой говорилось выше.
Практика форматирования
Таким образом, процесс создания файловой системы сводится к а)
выделению суперблока и записи общих параметров файловой системы, б)
созданию таблицы inodes (в UFS, в отличие от некоторых современных
файловых систем для Linux, все inode создаются раз и навсегда, а не
выделяются динамически, по мере надобности), и в) разметке блоков в
области данных. Из за все это, подобно незабвенной Катерине Матвевне,
отвечает одна-единственная программа, именуемая незамысловато --
newfs.
Команда newfs требует единственного аргумента -- имени файла
форматируемой партиции, например,
$ newfs /dev/ad0s1a
после чего все базовые свойства файловой системы будут определены по
умолчанию. Однако пользователь в силах влиять на них с помощью опций,
важнейшие из которых мы и рассмотрим (или -- определив их раз и
навсегда глобально, через sysinstall, но это -- тема отдельного
разговора).
Опция -b определяет размер логического блока файловой системы.
Минимальный размер его -- 4096 байт, максимальный, насколько я знаю,
определяется только здравым смыслов. А с точки зрения оного,
<<умолчальное>> значение в 16384 байт представляется разумным.
Опция -f устанавливает размер фрагмента блока. Рекомендуется
определить его в 1/8 размера блока, что по умолчанию и составит 2048
байта. Значения в 1/4 или 1/2 блока также допустимы, но очень не
рекомендуются в документации.
Опция -i очень важна -- она-то косвенно и устанавливает количество
записей в индексной таблице (то есть максимальное количество файлов в
файловой системе). Значение этой опции дается в байтах, отводимых на
элемент индексной таблицы, и должно быть кратным размеру блокового
фрагмента. Значение по умолчанию -- учетверенный объем оного, что
определяет средний прогнозируемый размер файла (8096 байт).
Еще одна интересная опция -- это -m, значение которой указывается в
процентах от суммарного объема дискового пространства отведенного на
партицию. И представляет собой объем, резервируемый от записи обычными
пользователями (но не root'ом -- тот всегда имеет возможность записать
свои действия на диск). Он определяется потому, что быстродействие
файловых операций в UFS просто катастрофически падает, когда
количество свободных блоков в области данных близко к исчерпанию
(проверено на практике). И потому некий объем файловой системы
резервируется принудительно (по умолчанию -- 8%).
С этой опцией связана еще одна, -o, которая определяет алгоритм
выделения свободных блоков данных при создании новых файлов. Дело в
том, что UFS в состоянии размещать их двумя способами. Первый --
методом плотнейшей упаковки с целью минимизации внутренней
фрагментации и экономии дискового пространства. И называется он
оптимизацией по объему (опция -o принимает значение space). Второй же
метод (-o time) обеспечивает быстрейшее выделение свободных блоков с
целью увеличения скорости создания файлов (то есть вопреки принципу
Леонида Ильича -- <<экономика должна быть экономной>>). Так вот,
умолчальное значение -o коррелирует со значением -m: если оно больше
или равно 8%, применяется оптимизация по времени, если меньше -- по
объему. Хотя явным образом можно указать прямо противоположные
значения.
Вообще-то, все приведенные выше опции очень важны, интересны и полезны
для общего образования, однако пользователю вряд ли придется к ним
прибегать: их значения по умолчанию, как и почти все во FreeBSD,
разумны и приемлемы в подавляющем большинстве случаев. А вот опция -U
при запуске newfs по умолчанию не задействуется. Обеспечивает же она
поддержку штуки крайне полезной -- механизма Soft Updates,
способствующему (парадоксально, но -- правда) как повышению
быстродействия файловых операций, так и устойчивости файловой системы.
Тема Soft Updates, однако, столь интересна сама по себе, что
заслуживает отдельного обсуждения, чем мы и займемся в следующем
разделе этой же заметки. А пока под рассмотрим отличия текущей
разновидности файловой системы FreeBSD, UFS2, от ее предшественницы --
UFS.
Все, что было сказано выше о файловой системе FreeBSD, относилось в
равной мере к обеим ее разновидностям. Главная особенность UFS2 -- то,
что она 64-разрядная и, соответственно, способна работать с дисковыми
объемами более терабайта (интересно, скоро это станет актуальным для
настольного пользователя? Судя по темпам дискобольства, срок этот не
за горами). В этой связи напомню, что длина записи в таблице inodes в
UFS2 удвоилась, и равна 256 байт.
Далее, в UFS2 включена поддержка расширенных атрибутов файлов, в
частности, ACL, но это существенно для сетевых администраторов. А вот
что может заметить пользователь -- то, что создание новой файловой
системы происходит быстрее (на больших дисковых разделах это
действительно заметно, что называется, органолептически). Происходит
это за счет т.н. <<ленивой>> инициализации inodes, хотя динамического
их выделения, как, например, в XFS, и нету.
А вообще, с точки зрения пользователя, различий между UFS и UFS2 можно
и не увидеть. Тем не менее, отказываться от UFS2 также оснований нет.
Тем более, что и newfs, о которой говорилось выше, и sysinstall, о
которой разговор впереди, по умолчанию ныне (в 5-й ветке) создают
именно ее. Если же требуется создать просто UFS (для совместимости с
версиями прежних веток, UFS2 не поддерживающих), это нужно сделать
принудительно, указав для newfs опцию -O 1.
Парадокс Soft Updates
При всех своих многочисленных достоинствах, файловая система FreBSD не
может похвастаться одним -- быстродействием. И это не смотря на то,
что в основе ее лежит обще-берклианская FFS -- быстрая файловая
система. Однако эпитет здесь выступает в сравнении с прежней Unix'овой
файловой системой -- s5, все вариации которой, как говорят знающие
люди, отличались исключительной задумчивостью. Если же сравнить
производительность файловой системы FreeBSD с родной для Linux Ext2fs
-- оно окажется не в пользу первой, особенно на операциях с большим
количеством мелких файлов.
Почему? Нетрудно ответить: вследствие принятого во FreeBSD по
умолчанию режима обращения с измененными файлами. Большинство
нормальных файловых систем способны функционировать в одном из трех
режимов:
* полностью синхронном, когда обновления и метаданных, и области
данных файла записываются на диск сразу вслед за его изменением;
* полностью асинхронном, при котором все изменения файла (и его
метаданных, и области данных) кэшируются в оперативной памяти и
реально записываются на диск в подходящее для того время;
* смешанном, реализующем синхронный механизм для измененных
метаданных и кэширование -- для модификаций области данных.
Очевидно, что первый режим обеспечивает наибольшую устойчивость
файловой системы к сбоям, второй -- наибольшее быстродействие файловых
операций (ценой возможности нарушения целостности файловой системы и
даже полного ее разрушения при аварийном завершении работы), а третий
обеспечивает как бы компромисс между первым и вторым решением.
Так вот, в файловой системе Linux (конкретно -- в ext2fs, Linux нынче
за родные признает много файловых систем) по умолчанию задействуется
полностью асинхронный режим работы, а во FreeBSD -- смешанный.
Конечно, это определяется при монтировании файловых систем, и с
помощью соответствующих опций команды mount (что я покажу в
соответствующей заметке) файловую систему FreeBSD можно заставить
работать полностью асинхронно. Однако резонные люди не рекомендуют это
делать категорически -- и, вероятно, имеют к тому основания (одна из
причин к тому станет ясной в конце заметки).
И действительно, в умолчальном режиме файловая система FreeBSD (в
сравнении с той же ext2fs) демонстрирует замечательную устойчивость.
За два с половиной года общения с этой ОС (а из них полтора пришлось
на селянские условия, когда неожиданное отключение электричества были
вещью более чем обычной) мне ни разу не пришлось столкнуться с
проблемами из-за аварийного завершения сеанса работы (в Linux'е такие
проблемы, до внедрения журналируемых файловых систем, возникали сплошь
и рядом).
Однако цена за это -- быстродействие. Вернее, отсутствие оного. И
проявляется это особенно наглядно именно при копировании большого
количества мелких файлов (процедура, весьма обычная при работе с
текстовыми, по преимуществу, материалами). Действительно, при этом в
синхронном режиме обновляется огромное количество файловых inodes,
тогда как собственно данных изменяется ничтожное по объему количество,
и их кэширование доставляет мало радости. В любом случае копирование
набранных в текстовом редакторе статеюшечек размером с эту заметку и
суммарным объемом в стандартный CD затягивается на вполне
чувствительное время (в отличие от Linux'а, где подобная операция
выполняется внешне мгновенно -- другое дело, что индикатор активности
жесткого диска может еще долго подмигивать).
Далее, не смотря на всю свою фактическую устойчивость, файловая
система FreeBSD, не будучи журналируемой, сама по себе не имеет
механизма гарантии собственной целостности. То есть: при аварийном
завершении работы, когда в файловой системе не устанавливается т.н.
бит чистого размонтирования (clean byte -- это один из важных
параметров файловой системы, записываемый в ее суперблоке при
корректном выходе из системы), в ходе процедуры последующей загрузки
принудительно вызывается программа проверки ее на предмет нахождения
противоречий между метаданными и областями данных (и их устранения). А
при современных объемах дисков (и, соответственно, файловых систем на
них) такая проверка может затянуться на часы. Конечно, это особенно
прискорбно для серверов, но и на настольной машине доставляет мало
положительных эмоций.
Проблема нарушения целостности существует и в Linux'е (по указанным
выше причинам -- даже в большей мере). И в Linux'е с нею борются
посредством журналирования, то есть опережающей регистрации изменений
метаданных (и, в некоторых случаях, даже и данных). Во FreeBSD же
борьба за целостность файловой системы велась исторически по двум
направлениям. Второе из них -- появившаяся в 5-й ветке фоновая
проверка целостности файловой системы, допускающая начало нормальной
работы сразу после аварийной перезагрузки машины. Поскольку это --
одно из принципиальных новшеств, скажу пару слов по сему поводу.
Для проверки целостности файловой системы во FreeBSD используется
утилита fsck (одноименная есть и в Linux -- для ext2fs, есть
аналогичные инструменты и для прочих файловых систем). Она может быть
запущена пользователем (вернее, root'ом) из командной строки. Однако
схема старта системы предусматривает ее автоматический запуск, если в
какой-либо из автоматически монтируемых файловых систем не обнаружен
бит чистого размонтирования. А поскольку fsck -- побитная операция, во
избежание тяжких последствий она обычно проводится на размонтированных
файловых системах. Что и было во FreeBSD вплоть до версии, как
минимум, 4.6 (более старших из 4-й ветки уже не видел). А вот в
версиях 5-й ветки, начиная с первой, более чем годичной давности,
developer'ской, проверка диска может выполняться на смонтированной и
готовой к работе файловой системе. И, соответственно, в фоновом режиме
после полной загрузки системы, параллельно с выполнением обычной
работы. Казалось бы -- пустячок, а приятно: затрудняюсь сказать,
сколько заняла бы полная проверка обычных ныне 80- или 120-гигабайтных
винтов.
Однако первым по времени реализации способом борьбы за целостность
файловой системы был механизм Soft Updates, обеспечивающий
одновременно (вернее, главным образом) и повышение быстродействия
файловых операций.
Сам по себе механизм Soft Updates (оставим этот термин без перевода --
варианты оного типа <<мягких обновлений>> не только не блещут
литературным изяществом, но и сути дела не проясняют) детально описан
в специальной статье Макказика и Ганджера, смысла пересказывать
которую я не вижу (благо она имеется в [30]русском переводе). В двух
же словах суть этого механизма -- в сведении к минимуму синхронных
операций записи без явно асинхронного манипулирования метаданными, с
одной стороны, но и без предварительного журналирования метаданных
(как в файловых системах типа ReiserFS или XFS) -- с другой.
Реализуется это, опять же говоря довольно грубо (детали реализации
моему пониманию недоступны -- каюсь) за счет так называемых
зависимостей обновления. Что такое эти зависимости -- интуитивно ясно
из примера создания нового (для простоты -- пустого) файла. Для этого
требуется:
* запись в таблице inodes, с заполнением полей типа файла, его
идентификатора, счетчика ссылок (со значением 1 -- каждый файл
должен принадлежать как минимум одному каталогу), ну и прочих там
-- прав доступа в соответствие с их маской, и так далее;
* изменение карты свободных/занятых inodes в блоке группы цилиндров
(соответствующий новому файлу inode должен быть помечен в ней
битом занятости);
* внесение записи вида <<идентификатор -- имя_файла>> в структуру
каталога, в котором новый файл создается, что обеспечивает ту
самую единственную ссылку в соответствующем поле inode файла.
С точки зрения целостности файловой системы, эти операции должны быть
выполнены именно в этой последовательности. То есть наличие в каталоге
имени файла с идентификатором незаполненного (еще не созданного или
уже уничтоженного) inode -- явный непорядок: именно для исправления
такого рода безобразий и запускается программа проверки диска после
аварийного завершения сеанса.
Выполнять связанные зависимостями операции обновления в синхронном
режиме -- долго (каждая потребует своего обращения к диску), в
асинхронном -- нет гарантии сохранения последовательности (обновления
в кэше могут быть записаны тогда, когда бог на душу положит). Так вот,
механизм Soft Updates обеспечивает, с одной стороны, контроль за
последовательностью выполнения зависимых обновлений (что способствует
целостности состояния файловой системы), с другой -- группирует их в
единую атомарную операцию синхронного обращения к диску, за счет
сокращения числа коих и растет производительность. В этом, насколько я
понимаю, и состоит объяснение парадокса Soft Updates -- неожиданного
увеличения и надежности, и быстродействия.
В общем, постарался объяснить, как смог и как сам понял -- за
подробностями к упомянутой статье. В дополнение только замечу -- во
избежание недоразумений: механизм Soft Updates не только не
гарантирует сохранности пользовательских данных, не сохраненных по
раздолбайству юзера перед крахом системы, но и не преследует такой
цели. Его призвание -- следить, чтобы файловая система всегда
представала по возможности в непротиворечивом виде. Впрочем, то же
можно сказать и о любой журналируемой файловой системе -- ни одна из
них не страхует от ошибок пользователя...
Теперь посмотрим, как же Soft Updates можно использовать. Если
создавать файловые системы через sysinstall -- все просто: там по
умолчанию включение этого механизма уже давно (версии примерно с 4.3)
предусмотрено для всех файловых систем, кроме корневой. Последнее
аргументируется соображениями безопасности, которые (для настольной
машины) не кажутся мне убедительными -- так что я включаю ее и здесь.
Хотя именно для корневой файловой системы Soft Updates не особо нужна:
при правильном разбиении диска и грамотной эксплуатации запись в нее
(после первичной установки) происходит только при инсталляции нового
ядра, а часто ли это проделывается в нормальных условиях?
При создании же файловых систем вручную, командой newfs, Soft Updates
автоматически не включается: это нужно сделать, как уже говорилось,
указанием опции:
$ newfs -U /dev/ad#s#?
Впрочем, если она при форматировании была забыта -- ничего страшного:
для всех разделов, кроме корневого, включить Soft Updates легко с
помощью команды tunefs. Для этого следует перейти в
однопользовательский режим (очень рекомендуется; я как-то обошелся без
этого, но лучше следовать советам резонных людей), что делается
командой
$ shutdown now
Размонтировать все файловые системы, кроме корневой (с ней все равно
этот номер не пройдет) командой
$ umount -Af
Дать команду
tunefs -n enable /dev/ad#s#?
для каждого раздела, в файловой системе которого требуется Soft
Updates. И, наконец, повторением команды
$ shutdown now
вернуться в многопользовательский режим. Перезагрузки, что характерно,
не потребуется.
В принципе, Soft Updates можно включить и для корневой файловой
системы, но для этого потребуется загрузка с внешнего носителя, типа
rescue-CD из штатного комплекта FreeBSD.
Да, забыл сказать, что механизм Soft Updates требует включения
соответствующей опции в конфигурацию ядра. Впрочем, по умолчанию в
ядре GENERIC это уже сделано -- важно только не отключить ее случайно
при пересборке.
Что же дает Soft Updates с точки зрения производительности? Как
оказалось, очень немало. В упоминавшейся выше статье приведены
результаты выполнения файловых операций в обычном синхронном режиме, в
режиме чисто асинхронном (при котором игнорируются все зависимости
обновлений), и в синхронном режиме с Soft Updates. Результаты этих
тестов показывают, что быстродействие операций записи и удаления
файлов с включением Soft Updates возрастает в 2 и 20 раз
соответственно, лишь на 5% уступая результатам чисто асинхронного
режима. Из чего следует резонность совета резонных людей -- не
включать асинхронный режим: использование его просто не обеспечивает
прироста производительности, оправдывающего снижение надежности.
Я в свое время (еще на FreeBSD 4-й ветки) провел серию сравнений
быстродействия файловых операций в UFS (как без Soft Updates, так и с
ней) и в файловых системах Linux (ext2fs, ext3fs, reiserfs).
Использовался массив в 4 Гбайт очень смешанного характера, от большого
количества мелких html'ок до нескольких объемных tiff- и avi-файлов,
то есть типичный набор данных настольного пользователя. Результаты
впечатляли. Если UFS в чистом виде проигрывала по скорости ext2fs в
4-6 раз на копировании и более чем в 10 -- на удалении файлов, то при
задействованном Soft Updates разница в скорости копирования не
превышала полутора раз, а скорость удаления практически сравнялась (в
пределах ошибки эксперимента). Обе же журналируемые же файловые
системы Linux не обнаружили отличий в быстродействии от UFS с Soft
Updates -- а ведь только их можно сравнивать между собой с точки
зрения формальной устойчивости...
Алексей Федорчук (alv@linux-online.ru, UNIX4all - http://linuxshop.ru/unix4all)
Опубликовано -- 15 февраля 2004 г.
Файловая система FreeBSD: иерархия и монтирование
Созданием разделов и файловых систем на них дело подготовки дискового
пространства к использованию не заканчивается. Все созданные файловые
системы нужно еще сделать доступными для FreeBSD. Для чего они должны
быть смонтированы -- то есть включены в единую иерархию каталогов и
файлов, для обозначения которой также используется название файловой
системы. Однако если [29]раньше речь шла о физической организации
данных, то теперь пора ознакомиться с ее логикой.
Логика файловой системы
Логически файловая система FreeBSD (как и любой Unix-системы)
организована по древовидному принципу: в основании ее лежит корень
(корневой каталог, обозначаемый символом / и именуемый также
root-каталогом; последнее не должно путать с каталогом /root, который
выполняет роль домашнего для суперпользователя). От корневого
каталога, который можно уподобить скорее стволу дерева, отходят ветви
-- вложенные в него подкаталоги, и побеги -- обычные файлы. Последних,
правда, немного: в версиях FreeBSD 5-й ветки это пара профильных
файлов -- /.cshrc и /.profile, на самом деле дублирующие профильные
файлы суперпользователя (в каталоге /root), некий энтропийный
(/entropy) файл и файл с описанием авторских прав на систему
/COPYRIGHT.
А вот подкаталогов в корневом каталоге довольно много, и некоторые из
них устроены внутри весьма сложно, содержа в себе изрядное количество
вложенных подкаталогов более глубоких уровней.
В принципе иерархия каталогов во всех Unix-системах похожа, поскольку
регламентируется, во-первых, многолетней традицией, во-вторых --
всякого рода стандартизирующими документами, в частности, FHS
(Filesystem Hierarchy Standard), который ныне доступен в [30]русском
переводе.
Стандарт FHS был разработан первоначально для упорядочивания структуры
каталогов в многочисленных дистрибутивах Linux. И лишь позднее он был
приспособлен для других Unix-подобных систем (в том числе и
BSD-клана). Однако именно иерархия каталогов FreeBSD может послужить
примером для образцового следования духу FHS. А буквально штучные
отступления в ней от его буквы всегда функционально обусловлены.
Стандарт FHS покоится на двух основополагающих принципах -- четком
отделении в файловой иерархии каталогов разделяемых и неразделяемых, с
одной стороны, и неизменяемых и изменяемых -- с другой.
Противопоставление разделяемых и неразделяемых каталогов обусловлено
изначально сетевой природой Unix вообще и FreeBSD в частности. То есть
данные, относящиеся к локальной машине (например, файлы
конфигурирования ее устройств) должны лежать в каталогах, отдельных от
тех, данные которых доступны с других машин в сети, локальной или
глобальной (примером чему являются не только пользовательские данные,
но и программы).
Суть противопоставления неизменяемых и изменяемых каталогов легко
пояснить на примере. Так, те же пользовательские программы по природе
своей должны быть неизменяемыми (вернее, доступными для модификации
только администратору системы, но не самому пользователю, применяющему
их в своей работе). В то же время эти программы при своей работе
генерируют не только файлы данных, скажем, тексты или изображения
(изменяемая их природа ясна без комментариев), но всякого рода
служебную информацию, типа log-файлов, временных файлов и тому
подобного). Каковая и должна группироваться в каталогах, отделенных от
собственно исполнимых файлов программ, необходимых для их запуска
библиотек, конфигурационных файлов и т.д.
Четкое следовании концепции отчленения разделяемых и неразделяемых,
неизменяемых и неизменяемых каталогов друг от друга позволяет, в
рамках единой древовидной файловой иерархии, обособить отдельные ее
ветви физически -- то есть в виде самостоятельных файловых систем,
размещенных на изолированных устройствах (дисках, дисковых слайсах,
партициях; в общем случае -- и на удаленных, связанных по сети,
носителях, но об этом не будет сейчас разговора). Резонов к тому много
-- и повышение быстродействия, и увеличение надежности, и просто
соображения удобства, -- но и о них сейчас речь не пойдет. Потому что
сейчас для нас важно только то, что эти ветви файлового древа должны
быть инкорпорированы в общую файловую систему.
В предыдущей заметке говорилось, что всякий файл (в том числе и
каталог) опознается системой не по ее имени, а по уникальному
идентификатору его записи в таблице inodes. Существуют средства для
того, чтобы эти файловые идентификаторы просмотреть. Одно из них --
команда ls с опцией i, которая выведет идентификаторы каждого
именованного файла. Данная для корневого каталога -
$ ls -i
она покажет нам несколько неожиданную картину (для упрощения из вывода
исключены сведения об обычных файлах и символических ссылках в корне,
а оставшиеся каталоги отсортированы по их идентификаторам)
2 ../
2 ./
2 dev/
2 home/
2 tmp/
2 usr/
2 var/
3 cdrom/
4 mnt/
5 root/
8257 dist/
8258 bin/
8294 proc/
8295 sbin/
16512 stand/
24768 etc/
24776 boot/
Из этого примера (относящегося к файловой системе машины, на которой
эти строки пишутся) видно, что аж 7 каталогов имеют одинаковые
цифровые идентификаторы, равные 2. Спрашивается, какая же здесь
уникальность?
С первыми двумя элементами списка разобраться легко: ./ представляет
собой обозначение текущего каталога (в данном случае корневого), а ../
-- каталога, родительского по отношению к текущему; а поскольку выше
корня в файловой иерархии по определению ничего нет, то он обозначает
самого себя. Так что неудивительно, что ./ и ../ имеют один и тот же
идентификатор -- это разные обозначения (жесткие ссылки, или, иначе,
дублирующие имена) для одного и того же, корневого, каталога.
А вот то же, как кажется на первый взгляд, значение идентификатора для
каталогов /dev, /home, /tmp, /usr, /var требует объяснения. Однако оно
-- простое: все это каталоги, в которые смонтированы самостоятельные
файловые системы, либо расположенные на отдельных устройствах --
дисковых партициях, как каталоги /home, /usr, /var, либо виртуальные
файловые системы, не надстраивающие какое-либо реальное дисковой
устройство (каталог /dev с файловой системой устройств и, в данном
случае, каталог /tmp, в который смонтирована файловая система в
оперативной памяти, разговор о которой еще предстоит). А поскольку
таблица inodes -- своя для каждой файловой системы, нет ничего
удивительного в том, что корень каждой из них идентифицируется числом
2 -- нумерация inodes в них идет в собственной системе отсчета.
Так вот, монтирование -- это и есть включение файловой с системы в
какой-либо из существующих в корневой системе каталог (не обязательно
непосредственно в корне, он может быть любой степени вложенности, что
проиллюстрируется чуть ниже). Без этого каталоги и файлы такой
монтируемой системы просто недоступны. Это важно понимать, когда
сталкиваешься выражениями вроде <<создать файловую систему /usr>>. Из
сказанного выше очевидно, что создается-то (командой newfs) просто
некая абстрактная файловая система, а свое <<имя>> она обретает только
в момент монтирования в указанный каталог.
Интересно, что и идентификатор каталога для монтирования (он еще
именуется точкой монтирования, mount point) обретается только в момент
монтирования. Чтобы убедиться в этом, проведем простой эксперимент. В
каталоге /mnt, предназначенном специально для монтирования временно
подключаемых файловых систем) можно увидеть три подкаталога --
/mnt/disk, mnt/iso, /mnt/usb (это в моей системе, я их создал для
собственного удобства; изначально каталог /mnt во FreeBSD пуст). При
старте системы в них ничего не монтируется, и обычное их состояние --
быть пустыми. Если просмотреть их идентификаторы, то можно видеть
нечто вроде такого:
$ ls -i1 /mnt
16:46 ttyp0
18 disk/
24 iso/
19 usb/
Теперь возьмем и смонтируем в /mnt/usb флэш-накопитель с
USB-интерфейсом (именно для этого я его и предназначал) и повторим
просмотр. И видим:
18 disk/
24 iso/
2 usb/
То есть идентификаторы каталогов, оставшихся пустыми (/mnt/disk и
/mnt/iso) не изменились, а идентификатор каталога /mnt/usb волшебным
образом изменился на 2. Ибо в момент монтирования он стал корневым для
своей собственной файловой системы и точкой отсчета для исчисления
inodes всех записанных на ней файлов.
Немного отвлечемся и вспомним о жестких ссылках, посредством которых
одному и тому же inode и относящимся к нему блокам данных могут быть
присвоены разные имена. Теперь понятно, почему все такие файлы-дублеры
должны лежать в одной файловой системе: ведь в разных файловых
системах -- своя, не совпадающая, нумерация inodes, и идентифицировать
их по номерам невозможно (иначе как бы система отличила каталоги /usr
и /var из нашего примера -- ведь имена файлов ей глубоко до лампочки).
Для символических же ссылок, имеющих собственные inode (собственно, и
ничего, кроме них) со своими идентификаторами, нумеруемыми в системе
отсчета файловой системы, в которой они находятся, такого ограничения
нет. И могут символические ссылки лежать где угодно (в том числе и на
удаленной машине -- не только на иной партиции).
Вернемся, однако, к примеру нашего корневого каталога. Из всего
рассмотренного видно, что целый ряд его ветвей лежит на отдельных
партициях и образует собственные файловые системы (собственно, именно
для этого мы и создавали и те, и другие). И, следовательно, все они
нуждаются в монтировании.
Практика монтирования
Целям монтирования служит команда mount, выполняемая либо в ходе
загрузки системы автоматически, либо -- вручную, из командной строки.
Собственно, в полном смысле автоматически в любом случае монтируется
только корневая файловая система. Не обязательно лежащая на диске --
при старте с rescue CD или иного страховочного носителя она может
располагаться на виртуальном диске в оперативной памяти. Однако
процесс монтирования корневой файловой системы столь же неизбежен, как
победа социализма в мировом масштабе: также, как социализм, не победив
в мировом масштабе, просто утрачивает способность к существованию (что
мы не так давно и наблюдали), так и ОС без корневой системы
существовать не может. В Linux это вызывает kernel panic mode --
примерно то состояние, в которое впали наши вожди лет 20 назад.
Правда, они оказались крепче Linux'а и оклемались довольно быстро --
так что до сих пор нас reboot'ят (или reboot? -- а мы крепчаем:)).
Впрочем, к делу монтирования, которое я попытаюсь вам сейчас
представить, это не относится.
Так вот, для монтирования всех файловых систем, кроме корневой,
необходимо предпринять некоторые действия. Сначала мы рассмотрим, как
выполнить их руками, а потом -- как увековечить в соответствующих
конфигурационных файлах.
Итак, команда mount. Собственно, это -- целое семейство программ,
каждая из которой призвана монтировать файловые системы определенных
типов -- не только UFS, но и любой из числа поддерживаемых FreeBSD.
Список таковых весьма обширен -- получить о нем представление можно,
просмотрев на сей предмет каталог /sbin:
$ ls /sbin/mount*
что даст нам в ответ
/sbin/mount /sbin/mount_msdosfs /sbin/mount_smbfs
/sbin/mount_cd9660 /sbin/mount_nfs /sbin/mount_std
/sbin/mount_devfs /sbin/mount_ntfs /sbin/mount_udf
/sbin/mount_ext2fs /sbin/mount_nullfs /sbin/mount_umapfs
/sbin/mount_fdescfs /sbin/mount_nwfs /sbin/mount_unionfs
/sbin/mount_linprocfs /sbin/mount_portalfs
/sbin/mount_mfs /sbin/mount_procfs
Каждая команда из этого списка отвечает за отдельный тип файловой
системы, к некоторым из которых мы вернемся дальнейшем. А пока заметим
только собственно /sbin/mount, предназначенную для работы с UFS и
UFS2.
Вызванная из командной строки, она требует двух аргументов -- имени
монтируемого устройства и точки монтирования (то есть каталога, в
который должна монтироваться лежащая на нем файловая система). Имя
устройства должно обозначать уже размеченную на существующем
BSD-слайсе патрицию с созданной на ней файловой системой UFS2 (UFS),
например,
$ mount /dev/ads0d /usr
смонтирует файловую систему на указанном разделе в каталог /usr корня
файлового древа. Если файловая система на устройстве не создана или
имеет тип, отличный от 4.2BSD, последует сообщение об ошибке --
указание на incorrect super block: в отличие от одноименной утилиты
Linux, сама по себе команда mount во FreeBSD распознавать тип файловой
системы не умеет.
К точке монтирования предъявляются следующие требования: а) каталог с
таким именем должен существовать к моменту монтирования, и б) быть по
возможности пустым. Первое -- обязательно, второе же -- не совсем.
Монтирование в каталог с какими-либо файлами пройдет беспрепятственно
(помнится, в Linux не так давно это вызывало крах системы), но все его
содержимое станет недоступным вплоть до размонтирования. И если файлы,
в нем содержащиеся, имеют играют существенную роль для какой-либо
подсистемы, это может вызвать всякие нехорошие последствия. Например,
если содержимое каталога /tmp будет блокировано монтированием туда
какой-либо файловой системы во время работы оконной системы X,
результатом будет скорее всего крах X-сервера. Благо, при
необходимости можно осуществить объединенное монтирование (см. ниже).
В указанной форме монтирование выполнится с некоторыми умолчальными
характеристиками: файловая система будет доступна для чтения/записи в
режиме т.н. noasync (том самом, при котором операции с метаданными
осуществляются синхронно, а операции с данными -- асинхронно).
Изменить это положение можно с помощью значений опции -o. Их довольно
много, однако практически главными на данном этапе для нас будут:
* async -- обеспечит полностью асинхронный режим (не смотря на
грозные предупреждения в предыдущих заметках, я потом расскажу о
ситуации, когда это может быть оправдано);
* sync -- напротив, включение полностью синхронного режима (правда,
не очень представляю, зачем это практически нужно);
* noatime -- очень полезная опция, которая предотвращает обновление
атрибута времени последнего доступа к файлам, чем немало
способствует производительности;
* rdonly -- монтирует файловую систему в режиме только для чтения
(иногда это бывает необходимо);
* union -- та самая опция, которая позволяет выполнить объединенное
монтирование, при котором прежнее содержимое каталога mount point
остается видимым; правда -- с некоторыми ограничениями -- см. man
(8) mount.
Есть еще несколько значений опции -o, запрещающих размещение на
смонтированной файловой системе файлов определенных разновидностей,
например, исполнимых (-o noexec), файлов устройств (-o nodev) или
файлов с т.н. битом суидности (-o nosuid), однако они имеют
практическое значение в основном для администраторов серверов и служат
целям безопасности. На настольной же машине обычной формой
монтирования будет нечто вроде этой:
$ mount -o noatime /dev/ads0d /usr;
$ mount -o noatime /dev/ads0e /var;
$ mount -o noatime /dev/ads0f /home
Все сказанное относилось только к монтированию файловых систем
FreeBSD. Однако на практике часто возникает необходимость инкорпорации
в ее древо каталогов файловых систем других типов. Особенно часто это
требуется для ISO9660 (обычная файловая система для всех
компакт-дисков, кроме Mac'овских) и FAT'ов разного рода. В этом случае
соответствующая случаю команда монтирования должна быть вызвана явно,
например,
$ mount_cd9660 /dev/acd0 /cdrom
для монтирования компакта, или
$ mount_msdosfs /dev/ad## /mnt
для FAT'а любого рода (включая FAT32). Впрочем, сделать это можно и
косвенно, указанием команде mount опции -t тип_файловой_системы. Так,
команда
$ mount -t ext2fs /dev/ad## /mnt/linux
смонтирует файловую систему Linux (если соответствующая возможность
включена в ядро). При этом стандартный mount для BSD-разделов просто
подменяется командой /mount_ext2fs, призванной монтировать разделы
ext2fs (и ext3fs тоже -- но, естественно, без всяких функций
журналирования). То есть форма
$ mount -t fstype ... ...
будет полным эквивалентом команды
$ mount_fstype ... ...
Все операции по монтированию файловых систем (в том числе и на сменных
носителях) во FreeBSD требуют прав суперпользователя. В числе значений
опции -o здесь, в отличие от Linux-варианта команды mount, нет
параметра user, разрешающего монтирование обычным пользователям.
Правда, есть несколько способов обойти это, но сейчас говорить о них
невместно.
Настройка автоматического монтирования
Однако на практике к ручному монтированию прибегают только для редко
используемых файловых систем. Все принципиально важные для
функционирования FreeBSD файловые системы монтируются автоматически
при старте системы, а часто используемые -- в полуавтоматическом, так
сказать, режиме.
Для автоматического монтирования программа mount запускается в
процессе начальной загрузки из инициализационных сценариев. Она
отыскивает свой конфигурационный файл -- /etc/fstab, и монтирует все,
что в нем обнаружит, за некоторыми (оговоренными ниже исключениями).
Сам по себе файл /etc/fstab генерируется автоматически при установке
FreeBSD, включая все необходимые для обеспечения жизнедеятельности
файловые системы. Однако в дальнейшем он может правится вручную с
целью внесения новых устройств для монтирования или дополнительных
опций для уже включенных устройств.
Файл /etc/fstab -- это простенькая база данных в текстовом формате
(разделение полей -- пробелами или табуляцией), включающая следующие
поля:
* Device -- имя файла устройства, на котором расположена файловая
система, аналогично первому аргументу команды mount при ручном ее
использовании;
* Mountpoint -- точка монтирования (соответствует второму аргументу
команды mount);
* FStype -- тип файловой системы, указываемый также, как значение
опции -t;
* Options -- дополнительные опции монтирования, аналогично значениям
опции -o;
* Dump -- условия выполнения резервного копирования файловой системы
утилитой утилитой dump;
* Pass# -- условия проверки файловой системы утилитой fsck.
В свежеустановленной FreeBSD /etc/fstab в обязательном порядке будет
включать следующие записи (пример для 1-го слайса Master-диска на 1-м
IDE-канале):
# Device Mountpoint FStype Options Dump Pass#
/dev/ad0s1a / ufs rw 1 1
/dev/ad0s1b none swap sw 0 0
Если последовать советам резонных людей (и умолчаниям sysinstall) и
выделить из состава корня некоторые ветки файловой системы, к
перечисленным добавятся (при автоматической разметке слайса через
sysinstall) еще и записи вроде
/dev/ad0s1d /var ufs rw 0 0
/dev/ad0s1e /usr ufs rw 0 0
/dev/ad0s1f /tmp ufs rw 0 0
Наконец, очень рекомендуется проследить, чтобы в наличии была еще и
строка
/dev/ad0s1g /home ufs rw 0 0
отвечающая за файловую систему с домашними каталогами пользователей.
Очевидно, что в поле Options можно добавить любые доступные (и
разумные) значения опции -o (через запятую, без пробелов), например,
noatime для всех файловых систем, а для /tmp -- еще и async, ведь для
содержимого этого каталога не предполагается сохранение после
перезагрузки.
Сказанное выше относилось к файловым системам, монтируемым при старте
автоматически. Однако никто не мешает сделать в /etcfstab записи для
систем, подключаемым время от времени -- в этом случае их можно будет
монтировать по упрощенной схеме (именно это я и имел ввиду выше под
полуавтоматическим режимом). Так, для CD-накопителя можно добавить
строку (на самом деле она автоматически появляется при генерации файла
/etc/fstab)
/dev/acd0 /cdrom cd9660 ro,noauto 0 0
в которой опции, как нетрудно догадаться предписывают отказ от
монтирования при старте (noauto) и режим <<только для чтения>> (ro).
После чего для монтирования CD достаточно будет указать только mount
point -
$ mount /cdrom
Аналогичные записи можно сделать для всех сменных накопителей (Zip,
USB-драйвов, даже флоппи-дисков) и для не-BSD разделов (FAT или
Ext2fs). К слову сказать -- монтировать файловые системы по прощенной
схеме можно сразу после внесения изменений в /etc/fstab, не дожидаясь
перезагрузки машины.
Размонтирование
Все задействованные файловые системы перед выключением питания или
перезагрузкой машины в обязательном порядке должны быть
размонтированы. При корректном завершении работы это осуществляется
автоматически, в результате чего каждая из доступных для записи
файловых систем (вернее, партиция, ее несущая) получает бит чистого
размонтирования в своем суперблоке.
Однако в ряде случаев (например, при подключении или отключении
механизма Soft Updates или для выполнения проверки на целостность)
возникает необходимость ручного размонтирования (и повторного
монтирования) файловых систем, для чего служит команда umount. Она
требует единственного аргумента -- указания точки монтирования
файловой системы, <<изымаемой>> из древа каталогов, например:
$ umount /tmp
Одной строкой можно размонтировать несколько файловых систем:
$ umount /usr /var /home
А можно -- все смонтированные файловые системы или все файловые
системы, перечисленные в файле /etc/fstab (кроме корневой), для чего
потребуются опции
$ umount -A
или
$ umount -a
соответственно. Есть и возможность размонтирования файловых систем
определенных типов путем указания значений опции -t. Так, команда
$ umount -t ufs
размонтирует только BSD-разделы, не затронув CD и всего остального,
что задействовано в системе.
Файловые системы в момент размонтирования не должны использоваться, то
есть не должно быть обращений к находящимся на них файлам. Так,
нахождение в каком-либо каталоге файловой системы -- достаточное
основание для отказа в ее размонтировании (с выдачей сообщения типа
device busy), почему ни одной из перечисленных выше команд и не
удастся размонтировать корневую файловую систему. А вот считывание
файла данных какой-либо программой -- не повод для отказа
размонтировать несущую этот файл систему (ведь при этом в общем случае
общение между файлом в памяти и файлом на диске происходит только в
момент записи изменений.
Впрочем, можно размонтировать и используемую файловую систему -- для
этого команду umount потребуется дать с опцией -f. Правда, это может
привести к ошибкам, так что без острой необходимости лучше к ней не
прибегать. И на корневую файловую систему опция принудительного
размонтирования воздействия не окажет.
Массовое монтирование
Для продолжения работы после выполнения низкоуровневых операций с
файловыми системами их потребуется смонтировать обратно. Это можно
сделать не только без перезагрузки, но и без нудного индивидуального
монтирования. Достаточно прибегнуть к опции -a:
$ mount -a
посредством которой будут смонтированы все файловые системы, для
которых имеются записи в /etc/fstab. При этом будет предпринята
попытка смонтировать и те из них, которые помечены флагом noauto.
Чтобы избежать этого, можно дополнительно определить тип файловой
системы. То есть команда
$ mount -a -t ufs
смонтирует только BSD-разделы, не покушаясь на CD или флэш-накопители.
А можно, напротив, исключить из процесса глобального монтирования
какие-то из перечисленных в /etc/fstab файловых систем, например,
ненужные в данный момент FAT'ы:
$ mount -a -t nomsdosfs
Преамбула вместо заключения
К слову сказать, команда mount без опций и аргументов (а в такой
форме, в отличие от всех рассмотренных выше случаев, ее может дать и
обычный пользователь) выведет список смонтированных в данный момент
файловых систем с указанием точки монтирования, условий оного и режима
работы. Например, для машины, на которой пишутся эти строки, вывод ее
будет выглядеть так:
/dev/ad0s1a on / (ufs, local, noatime, soft-updates)
devfs on /dev (devfs, local)
/dev/ccd0e on /var (ufs, local, noatime, soft-updates)
/dev/ccd1e on /usr (ufs, local, noatime, soft-updates)
/dev/ccd2e on /home (ufs, local, noatime, soft-updates)
/dev/md0 on /tmp (ufs, local, noatime, async)
Первая строка вывода показывает, что партиция /dev/ad0s1a смонтирована
у нас в корневом каталоге, несет на себе файловую систему UFS
(конкретно в данном случае -- UFS2, но в выводе команды mount они не
различаются) с задействованным механизмом Soft Updates, является
локальной (то есть расположена на диске этой машины -- сетевые диски
также монтируются командой mount) и не подвержена обновлению атрибута
atime.
А вот дальше идут строки для устройств и файловых систем, о которых не
было речи в предшествующих повествованиях. Более того, если мы
посмотрим на соответствующий наличной конфигурации файл /etc/fstab:
$ more /etc/fstab
/dev/ad0s1b none swap sw 0 0
/dev/ar0s1b none swap sw 0 0
/dev/ad0s1a / ufs rw,noatime 1 1
/dev/ccd0e /var ufs rw,noatime 2 2
/dev/ccd1e /usr ufs rw,noatime 2 2
/dev/ccd2e /home ufs rw,noatime 2 2
/dev/acd0 /cdrom cd9660 ro,noauto 0 0
/dev/da0s1 /mnt/usb ext2fs rw,noauto,noatime 0 0
/dev/md0 /tmp mfs rw,noatime,async,-s32m 2 0
то увидим, что одной из строк вывода (devfs on /dev (devfs, local)
вообще нет соответствия среди его записей. Что это за устройства и
файловые системы?
Относительно устройств типа /dev/ccd0? скажу пока только, что это
программные RAID-массивы (подробнее о них будет говориться позднее). А
вот devfs и mfs -- виртуальные файловые системы, о которых --
непосредственно в следующей заметке.
Алексей Федорчук (alv@linux-online.ru, UNIX4all - http://linuxshop.ru/unix4all)
Опубликовано -- 29 февраля 2004 г.
FreeBSD: файлы без партиций и партиции без файлов
В предыдущих заметках, явно или не явно, речь шла о файловых системах
определенного типа, которые так и называются -- disk based (или, шире,
block device based). То есть это -- файловые системы, надстраивающие
реальные физические устройства блочного типа. Для них, вне зависимости
от того, для какой операционки они предназначены, необходимо: создание
раздела, физического или логического, его форматирование и
монтирование в структуру каталогов ОС.
Однако FreeBSD (и не только она) поддерживает и еще одну группу
файловых систем, которые можно назвать виртуальными. Под ними не лежат
какие-либо физические устройства вроде дисков и иных накопителей,
место их базирования -- оперативная память. И соответственно, для их
использования не требуется ни разбиение диска, ни форматирование, а
подчас не нуждаются они даже в монтировании. К их числу принадлежат
procfs -- файловая система процессов, devfs -- файловая система
устройств, и mfs -- файловая система в оперативной памяти.
Procfs
Файловая система процессов была исторически первой из виртуальных
файловых систем, поддерживаемых FreeBSD, и ранее играла в ней большую
роль: именно через нее можно было получить информацию о системе с
помощью команд типа ps и top. Ныне, в версиях 5-й ветки, значение ее
упало, вплоть до того, что она не монтируется по умолчанию при старте,
хотя никто не запрещает сделать это вручную.
Однако без нее вполне можно обойтись, и вообще поддержка procfs более
не считается во FreeBSD обязательной (в отличие от Linux). Поэтому
здесь скажу о ней только два слова (к этому вопросу мы когда-нибудь
еще вернемся при рассмотрении процессов).
Перво-наперво, для использования procfs требуется поддержка в ядре --
в умолчальном GENERIC 5-й ветки таковая пока имеется. Заодно тут же
включается и поддержка Pseudo-filesystem framework (псевдофайловых
систем, что ли? Или, наоборот, файловых псевдосистем...) -- кроме
procfs для FreeBSD, она обеспечивает поддержку файловой системы
процессов в режиме совместимости с Linux (где без этого, насколько я
понимаю, обойтись трудно).
Далее, файловая система procfs монтируется (обязательно) в каталог
/proc командой
$ mount_procfs procfs /proc
В каталоге /proc она и отображает протекающие в системе процессы в
виде файлов, которые можно (обладая соответствующими правами)
просмотреть обычным образом. Каждому процессу соответствует
подкаталог, именем которого является идентификатор процесса (просто
номер в порядке запуска). Внутри такого подкаталога обнаруживаются
примерно такие файлы:
$ ls -1 /proc/##
cmdline
ctl
dbregs
etype
file@
fpregs
map
mem
note
notepg
regs
rlimit
status
Содержание тех из них, которые удается просмотреть (не для всех файлов
такое возможно -- многие в ответ на команду типа more выведут
нечленораздельную бинарную абракадабру или просто сообщение об ошибке
чтения, вне зависимости от прав доступа) -- имя запустившей процесс
команды (cmdline) и формат его исполнимого файла (etype), сведения об
используемых адресах памяти (map) и так далее.
Procfs практически не занимает на диске, в чем легко убедиться
командой df:
$ df -m
Filesystem 1M-blocks Used Avail Capacity Mounted on
/dev/ad0s1a 247 67 160 30% /
devfs 0 0 0 100% /dev
/dev/ccd0e 495 3 452 1% /var
/dev/ccd1e 9681 1251 7655 14% /usr
/dev/ccd2e 135194 11303 113075 9% /home
/dev/md0 31 0 28 0% /tmp
procfs 0 0 0 100% /proc
Те жалкие килобайты, которые показала бы команда без опции -m, уходят
на описание структуры ее каталогов. Так что отказываться от нее из
соображений экономии -- несерьезно. Хотя, повторяю, и большой
необходимости в ней также обычно не возникает: команды ps и top,
информирующие о протекающих процессах, ныне обходятся без нее (и
предоставляют сведения более полные и в более понятной форме).
Devfs
Поддержка файловой системы устройств, напротив, появилась во FreeBSD
недавно -- лишь в версиях 5-й ветки. Она, как ясно из названия,
включает в себя файлы устройств и монтируется (автоматически, при
старте системы, не требуя даже записи в /etc/fstab) в каталог /dev.
Чтобы понять всю новаторскую роль devfs, нужно вспомнить, как
происходило обращение с файлами устройств до ее появления (сначала --
в Solaris, затем -- в Linux и вот теперь, наконец, во FreeBSD.
А происходило оно так. Некий набор файлов устройств генерировался при
начальной установке системы. Каждый файл устройства характеризовался
своим старшим (major) и младшим (minor) номерами. Первый определял
класс устройств, например, диски, терминалы и псевдотерминалы,
параллельные или последовательные порты, и так далее. Младший номер
был идентификатором конкретного устройства в данном классе. Очевидно,
что сочетание старшего и младшего номеров должно быть уникальным.
Файлы устройств генерировались в некотором соответствии с реальностью,
но по принципу явной избыточности. Например, при наличии
IDE-контроллера, поддерживающего до 4-х устройств, создавались файлы
для всех теоретически подключаемых к нему дисков -- от ad0 до ad3,
даже если в наличии имелся только один. То же и с псевдотерминалами --
файлов вида pty* в каталоге /dev можно было обнаружить немерянно (и
понятно, почему -- ведь каждый запущенный в X-сессии экземпляр
эмулятора терминала вроде xtrem требовал своего такого устройства). В
результате каталог /dev приобретал объем просто необозримый.
И, тем не менее, подчас наличных файлов оказывалось недостаточно для
представления всех нужных устройств. И тогда пользователю приходилось
их создавать самостоятельно. Файлы для большинства распространенных
устройств можно было создать с помощью специально предназначенного
сценария /dev/MAKEDEV. Однако иногда он оказывался бессильным
(особенно для новых устройств, сценарием еще неучтенных), и
приходилось прибегать к чисто ручному созданию файлов устройств
командой mknod. Что было не так уж и трудно само по себе, но требовало
знания старшего номера создаваемого устройства (младший при этом
вычислялся легко).
Появление devfs избавило пользователя от этих забот. Отныне файлы
устройств пересоздаются автоматически при старте системы -- и только в
соответствии с наличным (и поддерживаемым текущей конфигурацией ядра)
железом, определяемым в ходе загрузки (и со списком которого можно
ознакомиться посредством команды dmesg). Если же в ходе работы
какого-либо устройства из числа поддерживаемых недостанет --
соответствующий ему файл будет создан сам собой. Чтобы убедиться в
этом, достаточно дать команду
$ ls /dev/pty*
до и после запуска в X-сессии очередного эмулятора терминала: можно
будет увидеть, что число файлов типа pty* после вырастет на единицу.
Файлы блочных устройств, типа программных RAID или memory disks, о
которых пойдет речь в следующей заметке, также создаются сразу после
их конфигурирования.
Более того, devfs сделала очень легким <<горячее>> подключение
устройств (типа USB-накопителей, цифровых камер и сканеров с этим
интерфейсом). Достаточно воткнуть USB-драйв в соответствующий разъем
-- и в каталоге /dev можно будет наблюдать появление соответствующего
ему файла типа /dev/da0.
Одна из приятных черт реализации devfs для FreeBSD, отличающая ее от
Linux-аналога -- отсутствие изменения номенклатуры устройств. То есть
жесткие IDE-диски, как были устройствами вида /dev/ad#, так ими и
остались. Не превратившись в жутких монстров вроде /dev/ide/..., что
вынуждено произошло в Linux. Второе отличие devfs во Free от ее
Linux'овой ипостаси -- возможность полностью игнорировать пресловутую
<<обратную совместимость>> (хотя обеспечить ее тоже никто не
запрещает). В Linux это также вынужденная мера, рассчитанная на
программы (низкоуровневые утилиты), которые о devfs не подозревают. А
во FreeBSD такой нужды не возникает -- все программы, напрямую
работающие с устройствами, являются неотъемлемой частью операционной
системы (к вопросу о преимуществах централизованной разработки).
Mfs
Файловая система MFS представляет собой частный случай более широкого
явления -- механизма memory disks, через который осуществляется также
поддержка виртуальных дисков в оперативной памяти (аналог RAM-дисков в
DOS и Linux) и доступ к файлам (например, iso-образам CD-дисков) как к
реальным устройствам (аналог loopback-устройств в Linux). Однако в
этой заметке мы ограничимся только рассмотрением собственно mfs -- о
RAM-дисках я смогу рассказать, когда у меня дойдут до них руки, а
обращение с файлами как с устройствами будет рассмотрено при описании
процесса записи CD-R/RW.
Назначение mfs -- заменить собой дисковые устройства там, где
требуется быстрая, но не обязательно долговременная, запись. То есть
-- для всякого рода промежуточных каталогов при
архивации/разархивации, пакетной конвертации графических файлов, а
также компиляции программ.
Наиболее целесообразно использовать mfs для монтирования в каталог
типа /tmp, предназначенный для хранения всякого рода временных файлов,
а также периодически задействовать ее под каталог /usr/obj, куда
помещаются промежуточные продукты компиляции при полном rebuilding'е
системы -- исполнение команды make world, и (по новой схеме этого
процесса) при пересборке ядра.
Ну, про целесообразность размещения временных файлов в оперативной
памяти -- думаю, ясно без комментариев. А вот про /usr/obj -- скажу
чуть подробнее.
При компиляции программ образуется изрядное количество объектных
модулей, которые нужны только в процессе сборки. После образования
исполнимых файлов и их инсталляции они оказываются не просто
ненужными, а иногда даже вредными (если потребуется пересборка
программы из того же дерева исходников, но с другими параметрами).
Поэтому возникает естественное желание отделить объектные файлы от
первозданного древа исходников, выделив под них отдельную ветвь
файловой системы.
С другой стороны, при сборке таких сложных программных комплексов, как
базовая система FreeBSD или ее ядро, создается очень большое
количество объектных файлов. Обычно они не велики по размеру, но ведь
каждый из них требует себе операции записи/чтения. Что, не смотря на
все усовершенствования Soft Updates, остается не самой сильной
стороной файловой системы UFS. Так что перенесение их с диска в
оперативную память должно дать некоторый выигрыш во времени при
операциях make world или пересборке ядра.
Правда, оценки такого прироста, встречающиеся в литературе, весьма
изменчивы -- от первых процентов до 10-15%. Собственно говоря, выигрыш
от компиляции в mfs очень зависит от того, что именно компилируется:
большое количество мелких пакетов может собираться просто <<с
песнями>>, для сборки же тяжеловесов вроде ядра или оконной системы X
прирост скорости может оказаться весьма скромным.
По моим измерениям, операция make world без монтирования mfs в
/usr/obj выполняется (на P-4/2,53 с 1 Гбайт памяти) в среднем за 23
минуты, с использованием mfs в качестве временного хранилища (512
Мбайт) -- за 21 минуту. То есть выигрыш от использования mfs
составляет менее 10%. Много это или мало -- каждый может решить для
себя, но ведь, что характерно -- абсолютно задарма.
Однако монтирование mfs в /usr/obj имеет еще и побочный полезный
эффект -- отпадает необходимость в выполнении операций типа make clean
для очистки дерева исходников от промежуточных продуктов компиляции:
перестройка <<мира>> и ядра при этом каждый раз будет выполняться с
<<чистого листа>>. Тоже вроде пустяк, но ведь невредно, и усилий не
требует ни малейших...
Во всяком случае, повредить производительности (при достаточном
количестве оперативной памяти, конечно, -- но ведь нынче и 512 ее
мегабайт вовсе не редкость) mfs ни в коем случае не может. В принципе,
размер файловой системы mfs можно определить и в размере большем, чем
наличествующей физически памяти. Ведь во FreeBSD физическое ОЗУ и
область подкачки на диске составляют единое адресное пространство --
виртуальную память. И по исчерпании первой под mfs будет
задействоваться раздел подкачки.
Казалось бы, это полностью обесценивает все преимущества mfs. Однако
-- не совсем. Потому что во FreeBSD работа виртуальной памяти
организована весьма эффективно. То есть сброс данных из ОЗУ на диск
происходит не при исчерпании памяти, -- своппингу подвергаются
страницы, к которым долго не происходит обращений. И в результате
непосредственно в ОЗУ, то есть области максимально быстрого доступа,
практически всегда находятся наиболее, так сказать, актуальные
фрагменты загруженных данных. А потому mfs способна дать некоторый
выигрыш даже при частичном переносе ее в раздел подкачки. Хотя,
конечно, наиболее резонно применять mfs при большом объеме физической
памяти -- исходя из общих соображений, от 512 Мбайт и выше.
В общем, думаю, что mfs почти в любом случае -- штука как минимум не
вредная. Так что остается лишь ее задействовать. Для чего требуется
поддержка ядром дисков в памяти (md -- memory disks) без дальнейшей
детализации, что уже имеется в GENERIC по умолчанию. А потом -- только
сконфигурировать mfs соответствующей командой:
$ mdmfs md /mount_point
В результате в каталоге /dev будет создан файл устройства -- md#, где
# -- порядковый номер виртуального диска, если ранее таковых не было
-- нулевой. Можно указать и вполне конкретный номер, например, md1.
Файловая система на нем образуется автоматически, без всяких там newfs
и монтируется в указанный каталог.
Создаваемая таким образом mfs будет безразмерной, то есть в
перспективе может занять всю виртуальную (RAM+swap) память. Если это
почему-либо нежелательно, размер mfs можно ограничить опцией -s --
задав ее значение в блоках (просто число), килобайтах (##k) или
мегабайтах (##m).
Можно указать и некоторые другие опции монтирования, как для обычных
disk-based файловых систем. Так, опция -S позволяет отказаться для mfs
от механизма Soft Updates (очевидно, что его действенность в условиях
обмена память-память сомнительна). А вот с помощью -o async можно
задействовать для mfs-ветви полностью асинхронный режим работы.
Который для нее никаких отрицательных последствий иметь не может --
все равно ее содержание пропадет при перезагрузке, вне зависимости --
аварийной ли, корректной (правда, и в сколь-нибудь существенном
выигрыше от него я также не уверен). Ну и, конечно, никакой
необходимости в обновлении атрибута atime mfs не испытывает, и потому
добавить к -o еще и atime -- просто сам бог велел.
Остается решить, сколько памяти отдать на растерзание mfs в каталогах
/tmp и /usr/obj. Объем под файловую систему /tmp во многом зависит от
сферы применения машины (десктоп ли это, или сервер). По умолчанию,
скажем, в sysinstall для нее предлагается отвести 256 Мбайт -- немного
в масштабах современных дисков, но отрезать от оперативной памяти --
жалко. Тем более что в типичном десктопе из них будут обычно заняты
какие-то сотни килобайт (в основном под временные файлы оконной
системы X и чего-нибудь вроде KDE). Так что я, например, при 512 Мбайт
RAM кинул под mfs в /tmp 32 Мбайт -
$ mdmfs -S -o async -s 32m md0 /tmp
и недостатка пока не испытал ни разу (повторяю, для сервера расчеты
могут быть совершенно другими). Убедившись, что так оно и есть, можно
предписать монтирование mfs в каталог /tmp автоматически, для чего
вписать в /etc/fstab строку
/dev/md0 /tmp mfs rw,noatime,async,-s32m
и на этом успокоится.
А вот под /usr/obj потребуется немало места. С целью выполнения
операций make world и make buildkernel я отвел под нее 512 Мбайт (из
1024). И по окончании обеих процедур объем mfs был исчерпан на 80% (на
68% -- после окончания make world). Это притом, что мой world
собирался чуть ли не в минимальной конфигурации -- практически все,
что можно запретить в /etc/make.conf, было запрещено. Так что, похоже,
512 Мбайт -- необходимый минимум для mfs в /usr/obj.
Очевидно, что даже при гигабайтном ОЗУ отвести такое его количество
под mfs на постоянной основе -- излишество нехорошее. Так что лучше
монтировать файловую систему /usr/obj только по мере надобности --
непосредственно перед пересборкой <<мира>> и ядра:
$ mdmfs -S -o async -s 512m md1 /usr/obj
размонтируя ее по завершении (впрочем, пересборка ядра все равно
потребует перезагрузки, и mfs в /usr/obj пропадет естественным
образом).
Кое-что о своппинге
В предыдущих заметках неоднократно, но между делом упоминалось о
разделах для своппинга -- пора уделить этому несколько слов
специально. Поскольку на самостоятельную заметку этот рассказ не
тянет, лучшего места, чем в повествовании про виртуальные файловые
системы, я для этого не придумал -- поскольку своппинг имеет
непосредственное отношение к виртуальной памяти.
Что такое своппинг -- знают, наверное, все. Это способ увеличения
доступного ОЗУ путем переноса редко используемых данных из оперативной
памяти на диск и извлечения их обратно по мере необходимости. Для чего
на диске создается либо специальный раздел, либо -- просто отдельный
файл подкачки.
Во FreeBSD принято задействовать под своппинг отдельную партицию в
BSD-слайсе. Хотя можно отдать на это благое дело и слайс целиком -- в
таком случае открываются перспективы совместного использования
своп-пространства FreeBSD и другими ОС, например, Linux. А вот об
использовании для подкачки файла я не слышал...
Обычно (это и настоятельная рекомендация, и одно из умолчаний
sysinstall) под раздел подкачки отводится объем дискового
пространства, равный удвоенному объему ОЗУ. Не испытывая обычно
напряженки с емкостью дисков, я всегда следовал этому правилу. Хотя
однажды (при обстоятельствах, описанных в следующей заметке) я сделал
раздел подкачки вдвое меньше рекомендованного: система установилась,
загрузилась и заработала без проблем.
Тем не менее, экономия на swap-пространстве не оправданна. FreeBSD
работает с ним иначе, чем, например, Linux. В раздел подкачки данные
из памяти перемещаются не по заполнении ее -- своппингу подвергаются
страницы памяти, к которым давно не было обращений. И потому, вне
зависимости от того, сколько имеется оперативной памяти и насколько
она загружена, некий минимум занятого своп-пространства будет
практически всегда, в чем можно убедиться с помощью команды top.
Так, на машине, на которой пишется эта заметка, в данный момент
загружен в консоли только редактор vim (не то чтобы это обычное
использование моей тачки -- я выгрузил все остальное специально,
эксперимента ради). Однако в выводе top можно видеть, что при
гигабайте общей памяти, из которой свободно более 900 Мбайт, объем
занятого свопа составляет примерно 150 Кбайт. При большом же
количестве загруженных приложений раздел подкачки будет задействован
более интенсивно -- для того, чтобы предоставить максимум памяти
активным в данный момент задачам.
Также не встречалось мне в документации и упоминаний о верхнем
ограничении на объем swap-раздела (подобно тому, как в Linux для
архитектуры PC он ограничен ныне двумя гигабайтами). Можно
предполагать, что такое ограничение теоретически существует, однако,
учитываю внутреннюю 64-разрядность FreeBSD (начиная с 5-й ветки), оно
лежит, видимо, за пределами практически достижимого.
Раздел для своппинга обычно создается в ходе первичной установки
FreeBSD. Собственно, при установке ее через sysinstall без него
обойтись не удастся -- если в ходе разметки диска отказаться от
создания раздела подкачки, - последует сообщение об ошибке. Однако
разделы эти можно создавать и в последующем, например, при подключении
нового диска: разнесение области подкачки на два раздела, лежащих на
подключенных к разным IDE-каналам дисках, как говорят, весьма,
способствует производительности (хотя если диски сидят на одном
канале, быстродействие обмена память-своппинг не только не возрастет,
но, скорее всего, снизится).
Количество разделов подкачки определяется соответствующей опцией при
конфигурировании ядра (по умолчанию в GENERIC не задействована). Если
придать ей значение большее, чем разделов имеется в реальности,
системой резервируется некоторое пространство для этого. Впрочем, в
документации к ядру чрезмерно увлекаться этим не советуют.
Создать swap-раздел можно или через тот же sysinstall, или -- вручную,
причем последнее -- не менее просто: достаточно вызвать программу
$ bsdlabel -e /dev/ad#
и в соответствие с описанным в посвященной тому заметке форматом
внести туда запись о партиции, которой необходимо только придать
литеру b в качестве обозначения и определить swap в качестве fstype
(не забыв, конечно, про оффсет и размер). Никаких файловых систем на
swap-разделе создавать не нужно (их на нем и нет). Не требуется также
действий типа mkswap, как это требуется в Linux: swap-раздел готов к
использованию сразу после его разметки.
Единственное, что еще нужно -- активизировать раздел подкачки. Это
делается командой
$ swapon /dev/имя_партиции
Та же команда без аргумента, но с указанием опции -a, активизирует все
разделы подкачки, записи для которых имеются в файле /etc/fstab.
Обратные действия -- деактивация своп-раздела или разделов, --
осуществляются командами
$ swapoff /dev/имя_партиции
для единичного устройства, или
$ swapoff -a
для всех устройств из /dev/fstab. А получить информацию о текущем
состоянии своп-разделов можно командой
$ swapinfo
вывод, который будет примерно следующим:
/dev/ad0s1b 1037312 148 1037164 0% Interleaved
/dev/ar0s1b 1037312 0 1037312 0% Interleaved
Total 2074624 148 2074476 0%
Вот, пожалуй, и все, что я хотел бы сказать о подкачке во FreeBSD. Да,
обычная рекомендация -- размещать swap-раздел как можно ближе к
нулевому треку любого диска, -- во FreeBSD выполняется как бы сама
собой (если не противодействовать этому специально): поскольку за
swap-партициями резервируется литера b, он размещается сразу за
корневым разделом, если таковой наличествует, или с самого начала
диска, если оного нет. Убедиться в этом можно, сравнив размещение
партиций в двухдисковой конфигурации (очевидно, что корневой раздел
может быть только на одном из них). Смотрим на первый:
$ bsdlabel /dev/ad0
# /dev/ad0:
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'tedit
d: 524288 2598912 4.2BSD 0 0 0
e: 10240000 3123200 4.2BSD 0 0 0
f: 142938288 13363200 4.2BSD 0 0 0
А теперь -- на второй:
$ bsdlabel /dev/ar0
# /dev/ar0:
8 partitions:
# size offset fstype [fsize bsize bps/cpg]
b: 2074624 0 swap
c: 156301312 0 unused 0 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
В обоих случаях swap-разделы занимают стратегически наиболее выгодные
(с точки зрения быстродействия) позиции.
Алексей Федорчук (alv@linux-online.ru, UNIX4all - http://linuxshop.ru/unix4all)
Опубликовано -- 30 марта 2004 г.
FreeBSD: как порадоваться RAID'у
Большая часть предыдущих заметок была посвящена ручной разметке дисков
-- созданию слайсов, партиций, файловых систем, а также монтированию
последних в древо FreeBSD. Однако на практике необходимость прибегать
к такого рода мануальной терапии возникает не так уж часто -- при
начальной установке заботу обо всех этих проблемах берет на себя
sysinstall. Причем все эти действия совершаются почти нечувствительно
для пользователя. Возникает вопрос -- а за каким же я столько
распинался на эти темы, если большинству пользователей с ними
столкнуться не придется?
Ответов, как обычно, несколько. Во-первых, я сам не так давно со всем
этим разобрался, и потому решил поделиться приобретенными навыками:-).
Во-вторых, всегда полезно понимать, что стоит за front-end'ными
утилитами, особенно -- за такой универсальной и многогранной, как
sysinstall. В третьих, есть несколько видов установки и настройки,
которые либо нельзя выполнить через sysinstall полностью, либо легче
сделать без нее. Наконец, в четвертых -- применение sysinstall для
послеустановочного конфигурирования иногда бывает нежелательным, в
ряде случаев она любит внести кое-какую отсебятину в уже настроенные
конфигурационные файлы. Не очень существенную, но, тем не менее,
требующую внимания.
Собственно говоря, очередную заметку цикла я собирался посвятить
детальному описанию sysinstall -- ее возможностей (весьма
многочисленных) и ограничений (некоторые из которых имеют место быть).
Однако вовремя вспомнил, что эта тема хорошо освещена и в
[29]Handbook'е, и в [30]Иллюстрированном руководстве по установке
FreeBSD. Да и в своей книге про FreeBSD (А.Федорчук, А.Торн. FreeBSD:
установка, настройка, использование. СПб.: БХВ-Петербург, 2003) я
немало страниц уделил sysinstall и ее применению. В частности, один из
разделов ее так и назывался -- <<Алгоритм идеальной установки>>, так
что повторяю -- читайте меня, как говорил Бернард Шоу молоденьким
девушкам:-).
И потому в этой заметке я остановлюсь на одном из частных вопросов
установки FreeBSD -- на программном RAID-массиве нулевого уровня. А
заодно вернусь к идеальной инсталляции системы -- как это видится мне
теперь, по прошествии полутора лет.
Сразу оговорюсь, что установка производилась на машину с вышесредними
ресурсами, в частности, гигабайтом памяти и двумя дисками по 80 Гбайт
каждый (плюс в запасе имелся еще и 20-гигабайтник для резервного
копирования данных), так что не стояло ни проблемы экономии ресурсов,
ни задачи сохранения имеющихся данных. Однако ныне такие конфигурации
не выглядят чем-то из ряда вон выходящим.
Несколько слов о железе
Эти заявленные несколько слов могут потребоваться в дальнейшем. Итак,
дано:
* процессор Pentium-4/2,53;
* материнская плата Albatron на чипсете i845PE с дополнительным
контроллером IDE-RAID/SerialATA имени Promise FastTrak 376;
* память -- два модуля DDR333, по 512 Мбайт каждый, беспородные
(квази-Samsung);
* первый винчестер (Seagate Barracuda IV, 80 Гбайт) мастером на 1-м
встроенном IDE-канале;
* второй винчестер (Seagate Barracuda же IV, 80 Гбайт), единственным
устройством на IDE-RAID/UATA133;
* CD-R/RW (модель непринципиальна) слейвом на втором встроенном
IDE-канале;
* прочее, для работы необходимое, но в данном контексте рояля не
играющее.
Собственно, основным для дальнейшего являются RAID-контроллер и диски.
Так вот, этот самый RAID был сделан так, что массив на нем можно было
устроить из трех (ей же ей, так в документации) дисков -- одного на
разъеме UATA133 и двух -- на SerialATA (именно столько их и было).
Причем каждое устройство должно было быть мастером на своем разъеме, к
коим устройств типа CD ROM подключать не следовало (и действительно,
не работали). А аппаратно RAID'ы поддерживались уровней 0 и 1
(интересно, как это можно устроить mirroring для трех устройств -- но,
повторяю, так в документации было сказано.
Хотя вопросы аппаратного RAID'а меня не волновали -- дисков SerialATA
у меня не было, переходника Serial/Parallel ATA -- также. Так что
оставалось озаботиться только RAID'ом программным.
Я позволил себе задержаться на конфигурации потому, что она доставила
мне немало веселья при общении с Linux'ами. Теоретически я всегда
знал, что два современных винта на одном IDE-канале -- вещь не самая
быстрая. Но насколько она не быстра -- понял, только когда (в Gentoo
Linux, а затем -- в самостройном) устроил на этом хозяйстве (две
Барракуды на 1-м IDE) LVM-разделы. Оказалось, что даже перенести
второй диск мастером на второй канал (в паре с CD) -- и то быстрее
было (хотя тогда началось экстремальное торможение при записи с CD). А
целых три разъема дополнительного FastTrak'а бездействовали -- ни одно
ядро Linux (включая 2.4.21) видеть на нем винтов не желало в упор
(собственно, конечно, только винтов на Parallel ATA, но, думаю, что и
с сериальными была бы та же история). Так что когда Free пять-первой,
еще беты, этот винт увидела -- был весьма рад...
Что же касается дисков -- подчеркну, что они были не только одного
размера, но и одной модели, куплены в одном месте с разбежкой в
пару-тройку месяцев. Тем не менее, в них обнаружилась одна странность,
о которой будет сказано в свое время.
Почему RAID
Собственно говоря, для использования двух винчестеров под одной ОС
RAID-массив вовсе не обязателен -- достаточно было бы создать на
втором BSD-слайс, разметить его как одну партицию, создать на нем
файловую систему и смонтировать ее в один из подкаталогов
/home/user_имя_рек (мой домашний каталог -- главный пожиратель
дискового пространства). Просто, но не верх удобства.
Нужно все время помнить, что пользовательский каталог на самом деле не
только образован двумя файловыми системами, но и лежит на двух винтах.
Что, кроме всего прочего, накладывает ограничения на жесткие ссылки
внутри него. Мы ведь помним, что жесткие ссылки могут существовать
только в единой партиции. А для чего они нужны в домашнем каталоге --
ответить не трудно: это один из простых и дешевых (с точки зрения
расхода, как дискового пространства, так и времени) подстраховаться от
случайного удаления данных. Смахнешь, бывалыча, в азарте каталог,
показавшийся ненужным, хватишься -- ан глянь, он в виде жесткой ссылки
сидит где-нибудь в /home/user_имя_рек/dubles_data, и есть не просит...
Так что организовать два диска в виде единого пространства --
безусловно, удобнее. А для этого в природе предусмотрено два механизма
(кроме аппаратного RAID'а, но с ним, как уже говорилось -- облом):
программный RAID и механизм логических томов. Последний, насколько я
понимаю, встроен в файловую систему JFS, относительно поддержки
которой во Free информация промелькнула. Однако в текущей версии
(5.1-STABLE) никаких упоминаний на сей счет я не обнаружил -- в файле
описания конфигурации ядра /usr/src/sys/conf/NOTES про JFS не
говорилось ни слова. Да и от краткого с ней знакомства под Linux'ом
впечатлений чего-то выдающегося она не оставила...
Так что оставался только программный RAID. Разумеется, level 0 --
поскольку зеркалирование просто не соответствовало задаче, а level 5
показался сложным и неоправданным. Вообще, ИМХО, RAID-массивы с
избыточностью на настольной машине -- баловство: от ошибок
пользователя (причины 99% потери данных в домашних условиях) они не
страхуют (а иногда способны даже усугубить их последствия). От
аппаратных же сбоев -- только в том случае, если в столе лежит
запасной винчестер на смену рухнувшему. Ситуация, вероятно, не редкая
для админа локальной сети -- но практически исключенная на дому; по
крайней мере, если бы у меня завалялся ненужный винчестер, я нашел бы
десятки способов пристроить его к делу...
Изучение вопроса показало, что под FreeBSD, как это в ней обычно
бывает, есть не один способ реализации программного RAID-0:
исторический (вернее, в масштабах индустрии -- почти доисторический)
ccd и более современный vinum. Последний, представляя собой, как можно
догадаться из его man-страницы, нечто вроде менеджера логических
томов, считается более гибким. Однако я остановился на ccd --
рациональное объяснение этому дать затрудняюсь (разве что какие-то
непонятки с лицензией на vinum).
Подготовка к слиянию
Итак, ccd (Concatenated Disk driver), что в переводе означает --
драйвер слияния дисков. Средство, как я уже сказал, весьма древнее --
man-страница датирована 1995 г., -- а значит, проверенное временем.
Позволяет создавать программные RAID-массивы типа нулевого (stripping)
и первого (mirroring) уровней. Как уже говорилось, меня интересовал
только нулевой.
И тут обнаружилось, что и построение RAID'а средствами ccd может быть
выполнено двумя способами. Согласно первому, в соответствие с заветом
великого Ленина, прежде чем объединиться, следовало решительно
размежеваться, согласно второму -- наоборот.
Суть второго способа -- интуитивно понятна (и аналогична построению
RAID'а в Linux с помощью mdtools): два дисковых раздела одинакового
объема сливаются воедино, а потом это объединенное пространство
делится на партиции под нужные файловые системы (типа /usr, /var,
/home). Первая схема выглядела в описании более сложной -- сначала
деление обоих дисков на симметричные партиции под будущие файловые
системы, а потом попарное их слияние. Тем не менее, именно второй
способ показался мне, уж не знаю, обоснованно или нет, идеологически
более правильным. На нем я и остановился.
Важное замечание: в отличие, опять же, от Linux, во FreeBSD разместить
на программном RAID'е (средствами ли ccd, или vinum, без разницы)
корневую файловую систему нельзя. Поэтому прежде чем заниматься его
построением, необходимо систему установить хотя бы в минимальном
объеме. К чему я и приступил.
Итак, грузимся с инсталляционного CD (можно ограничиться и
мини-диском) и попадаем в sysinstall. Тут быстро проскакиваем стадию
начального конфигурирования опций -- я здесь обычно только заменяю
умолчальный редактор ee на любимый joe; в некоторых случаях, возможно,
есть смысл присмотреться к опциям создания файловых систем (Newfs
Args), хотя умолчальные -b 16384 -f 2048 видятся мне разумными. И
отправляемся с пункт Custom главного меню, где выбираем подпункт
Partition, отвечающий за создание слайсов.
Тут я столкнулся с первой неожиданностью: хотя диски мои казались
одинаковыми по всем параметрам, sysinstall обнаружила в них разную
геометрию, причем про один упорно утверждала, что она неправильна.
Меня это несколько смутило, я вышел из sysinstall, загрузился с
rescue-CD и вручную разметил (для страховки) оба диска в интерактивном
режиме -- командами
$ fdisk -i /dev/ad0
и
$ fdisk -i /dev/ar0
Правда, потом я понял, что необходимости в этом не было -- sysinstall
с подобными коллизиями справляется автоматически (а при необходимости
скорректировать геометрию диска вручную можно прямо из нее). Но о
потраченных усилиях не жалею -- в итоге появился сюжет для одной из
предыдущих заметок -- про практику дискодробительства.
Оба диска были размечены в эксклюзивном режиме (помещения на них
других ОСей не предполагалось, на сей предмет у меня был винт в
запасе). После чего я вернулся к установочному диску и sysinstall,
перейдя сразу к пункту Label (то есть разметке партиций.
Редактор разметки из sysinstall (Disk Label Editor) предусматривает
режим автоматического разбиения BSD-слайса на партиции, создаю
следующую конфигурацию разделов:
Part Mount Size Newfs
---- ----- ---- -----
ad0s1a / 256MB UFS
ad0s1b swap RAM*2 SWAP
ad0s1d /tmp 256MB UFS+S
ad0s1e /var 256MB UFS+S
ad0s1f /usr ост. UFS+S
Я предполагал оставить непосредственно на BSD-разделе только корневую
файловую систему, все остальное же перенести на конкатенированные
партиции, а swap-раздел разнести на оба физические диска. И потому
оставил только партиции a (в предложенном по умолчанию размере) и b (в
размере вдвое меньше). Практика показала, что 256 Мбайт за глаза
хватает для минимальной установки FreeBSD (а именно ею я и собирался
ограничится -- см. чуть ниже).
Должен заметить, что я попытался разметить разделы под дальнейшее
применение ccd непосредственно из sysinstall. Не сказать, чтобы ничего
не получилось, но кое-какие странности имели место. В частности, при
попытке разметки второго диска регулярно возникали ошибки при
определении последней партиции -- после того, как я отводил гигабайт
на swap, по полраздела под будущие конкатенированные /var и /usr (от
раздела под /tmp я отказался, так как предполагал вынести его на mfs
-- см. [31]предыдущую заметку), на попытку создать из остатка
полураздел для будущего /home следовало сообщение о нехватке места.
Правда, если создавать все это в обратном порядке, то есть сначала
разделы под файловые системы, а уже потом -- под swap, все вроде
проходило. Но это мне все равно показалось неправильным, и я оставил
свои попытки, решив вернуться к разметке партиций для ccd руками,
после установки базовой системы.
А из базовой системы я выбрал только пункт собственно base и
man-страницы (дабы не остаться с ccd один на один). В итоге вся
инсталляция уложилась у меня менее чем в 150 Мбайт. Забегая вперед,
скажу, что после вынесения из корневой партиции /var и /usr и досборки
(через make world) недостающих, но нужных компонентов (системы
безопасности, например -- без нее из портов или пакетов даже links не
собирается) в ней оказалось занятым всего 67 Мбайт. Конечно, при make
world я от многого отказался, но все равно: умолчальный размер
корневой партиции дается sysinstall с очень большим запасом, и при
недостатке дискового пространства его спокойно можно урезать вдвое
(повторяю, при вынесении /var, /usr и, конечно же, /home в отдельные
разделы).
По завершении разметки диска и установки базовой системы я,
отказавшись от установки пакетов, выполнил минимальный комплекс
настроечных действий: определил пароль для root'а (аккаунт для
обычного пользователя создавать пока нецелесообразно), сконфигурировал
консоль для работы с кириллицей (на всякий случай) и настроил мышь
(без консольной мыши жить несколько неуютно), а также удалил все
ненужные мне (то есть -- почти все вообще) стартовые сервисы. После
чего вышел из sysinstall, перезагрузив машину.
Система, не смотря на свою предельную урезанность и вдвое сниженный
объем swap'а, загрузилась нормально. Следовало приступать к разметке
партиций под ccd.
Авторизовавшись root'ом, я перво-наперво подмонтировал свой дежурный
исходняк-CD и из записанного на нем тарбалла собрал любимый редактор
joe, определенный ранее в качестве системного. Версии joe из портов
или пакетов FreeBSD, что стабильная, что developer'ская, устарели,
поэтому я просто распаковал архив в /usr/local/src:
$ mkdir /usrlocal/src
$ cd /usrlocal/src
$ tar xzvf /cdrom/src/joe-2.9.8.tar.gz
и, перейдя в образовавшийся каталог, выполнил конфигурирование, сборку
и установку:
$ cd joe-2.9.8
$ ./configure --bindir=/bin
$ make
$ make install
Опция --bindir=/bin предписывает установить исполнимый файл joe
непосредственно в /bin, который при любых дальнейших манипуляциях
останется в корневом разделе: всегда полезно, чтобы любимая командная
оболочка и редактор, выполняющий роль системного, находились
непосредственно в корне -- на случай действий в однопользовательском
режиме и всякого рода ремонтно-восстановительных работ.
Теперь -- собственно разметка партиций. Перво-наперво -- опять же
переход в однопользовательский режим -- вообще, лучше взять за правило
все действия, связанные с разметкой дисков, выполнять из него -- чисто
для страховки.
Далее, вооружившись bsdlabel, запускаемой с опцией -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 (256 Мбайт) и /usr
(5 Гбайт), предназначив все оставшееся пространство (около 65 Гбайт --
не будем забывать, что объем моих дисков исчислялся в гигабайтах,
принятых среди астрологов, хиромантов и производителей дисков, то есть
реально составлял по 76 истинных гигабайт) под половинку от /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/ar0s1), на котором
создал парные к первому разделы под swap (1024 Мбайт), /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
Можно видеть, что, не смотря на все мои усилия по ручной коррекции
геометрии, добиться полной идентичности мне не удалось, но на практике
это ничему не помешало. Вероятно, с точки зрения полной симметрии в
начале второго диска следовало оставить 256 Мбайт неразмеченного
пространства, зеркального по отношению к корню первого, но я этого не
сделал (и вреда, как будто, ни малейшего). А так неиспользованный
объем диска остался в самом его конце.
Конкатенируем помаленьку
Все предыдущие действия можно было бы проделать и через sysinstall (с
приведенными выше оговорками). Но теперь наступает время конкатенации
партиций -- и для этого в sysinstall средств как будто бы не
предусмотрено. Но зато имеется специально для этого предназначенная
утилита ccdconfig. Вооружаюсь соответствующей man-страницей -- man (8)
ccdconfig, -- и выясняю, что и эту процедуру можно проделать двумя
разными способами. Правда, оба требуют перехода в однопользовательский
режим.
Первый способ -- последовательный запуск ccdconfig для каждой пары
сливаемых партиций примерно таким образом:
$ ccdconfig ccd0 128 none /dev/ad0s1d /dev/ar0s1d
$ ccdconfig ccd1 128 none /dev/ad0s1e /dev/ar0s1e
$ ccdconfig ccd1 128 none /dev/ad0s1f /dev/ar0s1f
Где ccd# -- имя создаваемого RAID-устройства, 128 (для примера -- это
умолчальное значение) -- размер (в Кбайт) блоков чередования записи
данных на парные диски (понятно выразился? -- как это сказать более по
русски, не придумал), флаг none отменяет зеркалирование (то есть
создает именно sripped-массив, насколько я понял; чтобы сделать массив
уровня 1, потребовалось бы указать флаг CCDF_MIRROR или его
шестнадцатеричное значение -- 0x04). Аргументы понятны -- это имена
файлов партиций, которые подвергаются конкатенации.
В результате в каталоге /dev будут автоматически созданы новые
устройства -- /dev/ccd0, /dev/ccd1, /dev/ccd2 (напоминаю -- речь идет
о версии 5.1, использующей файловую систему устройств; в версиях 4-й
ветки эти устройства потребовалось бы предварительно создать скриптом
/dev/MAKEDEV или командой mknod), а в каталоге /etc возникнет
конфигурационный файл ccd.config.
Второй способ -- создать предварительно конфигурационный файл
/etc/ccd.conf (которому на самом деле можно дать произвольное имя и
поместить где угодно) в текстовом редакторе, и описать в нем
объединяемые примерно таким образом:
# ccd ileave flags component devices
ccd0 128 none /dev/ad0s1d /dev/ar0s1d
ccd1 128 none /dev/ad0s1e /dev/ar0s1e
ccd2 128 none /dev/ad0s1f /dev/ar0s1f
После чего запустить ту же утилиту конфигурации следующим образом:
$ ccdconfig -C
в результате чего все необходимые сведения будут взяты из
/etc/ccd.conf (если конфигу дали другое имя -- следует указать его как
аргумент с полным путем), устройства благополучно созданы.
Я проделал процедуру конкатенации обоими способами -- одинаково просто
и с идентичным (то есть неизменно превосходным) результатом. К слову
-- сбросить настройки ccd (если они почему-либо не устраивают) можно
командой
$ ccdconfig -U
после чего они безболезненно переконфигурируются заново.
Завершающие штрихи
Дальнейшее обращение с конкатенированными массивами происходит точно
так же, как и с обычными партициями: то есть их нужно разметить на
BSD-разделы, на которых создаются файловые системы, которые
монтируются в целевые каталоги. За одним исключением -- прибегнуть к
помощи sysinstall по-прежнему не удастся (по крайней мере, у меня не
получилось), так что вся надежда только на собственные руки.
Итак, для начала размечаем созданные массивы:
$ 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). Необходимости указывать размеры блока, фрагмента и прочего --
нет, эти значения будут определены при создании файловой системы. Что
и проделываем:
$ newfs /dev/ccd0d
$ newfs /dev/ccd1d
$ newfs /dev/ccd2d
Теперь созданные файловые системы остается только смонтировать в
предназначенные для них каталоги /var, /usr, /home. Однако если
последний девственно чист (не зря же мы отказались от создания
пользовательского аккаунта при постинсталляционной настройке), то в
прочих -- имеют место быть файлы, не очень многочисленные (установка
ведь велась по принципу минимализма), но жизненно важные для работы
системы. Так что предварительно их следует перенести на новые,
конкатенированные, файловые системы.
Со старым каталогом /var это проходит без проблем: монтируем
предназначенный для него ccd-раздел в какую-нибудь специально
созданную точку (например, /mnt/tmp)
$ mount /dev/ccd0d /mnt/tmp
и просто перемещаем все содержимое:
$ mv /var/* /mnt/tmp
С каталогом /usr поступаем также:
$ mount /dev/ccd1d /mnt/tmp2
$ mv /usr* /mnt/tmp2
Если получается -- все хорошо. Хотя тут возможны осложнения, если
находящиеся в старом /usr файлы как-то используются в текущий момент
системой. Конечно, при корректном переходе в однопользовательский
режим такого случиться не должно, но чем черт не шутит. Так что не
исключено, что для переноса файлов из /usr потребуется перезагрузка с
rescue-CD (на деталях останавливаться не буду).
Тем или иным образом перенеся содержимое старых каталогов в новые
конкатенированные файловые системы, остается только прописать их в
/etc/fstab примерно таким образом:
/dev/ccd0e /var ufs rw,noatime
/dev/ccd1e /usr ufs rw,noatime
/dev/ccd2e /home ufs rw,noatime
После чего -- перезагрузка и радость от обретенных RAID'ов. Насколько
значительная с точки зрения быстродействия -- строго, то есть
количественно, судить не возьмусь. Субъективно прирост быстродействия
незначительный. Однако и падения оной также не наблюдается. Так что
затраченные усилия вполне окупаются удобством обращения с
конкатенированными партициями...
Алексей Федорчук (alv@linux-online.ru, UNIX4all - http://linuxshop.ru/unix4all)
Опубликовано -- 15 апреля 2004 г.
Несколько поправок.
Параграф - Немного о "геометрии":
"количество цилиндров определяется объемом диска" -- количество цилиндров определяется количеством треков на диске.
"...255 треков нарезается на 63 сектора каждый, что в совокупности дает 16065 блоков на цилиндр." -- Если на диске 255 треков и 63 сектора, то 16065 блоков на диск (или блин). Чтобы узнать сколько блоков на цилиндр, нужно узнать сколько треков в цилиндре и умножить на 63 сектора.