В предыдущих заметках, явно или не явно, речь шла о файловых системах определенного типа, которые надстраиваюют реальные физические устройства типа типа дисковых и прочих накопителей. Для них, вне зависимости от того, для какой операционки они предназначены, необходимо: создание раздела, физического или логического, его форматирование и монтирование в структуру каталогов ОС.
Однако FreeBSD (и не только она) поддерживает и еще одну группу файловых систем, которые можно назвать виртуальными. Под ними не лежат какие-либо физические устройства вроде дисков и иных накопителей, место их расположения - оперативная память. И соответственно, для использования их не требуется ни разбиение диска, ни форматирование, а подчас не нуждаются они даже в монтировании. К их числу принадлежат procfs - файловая система процессов, devfs - файловая система устройств, и mfs - файловая система в оперативной памяти.
Procfs
Файловая система процессов была исторически первой из виртуальных файловых систем, поддерживаемых FreeBSD, и ранее играла в ней большую роль: именно через нее можно было получить информацию о системе с помощью команд типа ps
и top
. Ныне, в версиях 5-й ветки, значение ее упало, вплоть до того, что она не монтируется по умолчанию при старте, хотя никто не запрещает включить выполнить монтирование procfs вручную.
Однако без нее вполне можно обойтись, и вообще поддержка 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*
после вырастет на единицу. Файлы таких устройств, как диски в оперативной памяти (memory disks), о которых пойдет речь ниже, или программные RAID-массивы, будущие предметом следующего раздела, также создаются сразу после их конфигурирования.
Более того, devfs сделала очень легким "горячее" подключение устройств (типа USB-накопителей, цифровых камер и сканеров с этим интерфейсом). Достаточно воткнуть USB-драйв в соответствующий разъем - и в каталоге /dev
можно будут наблюдать появление соответствующего ему файла типа /dev/da0
.
Одна из приятных черт реализации devfs для FreeBSD, отличающая ее от Linux-аналога - отсутствие изменения номенклатуры устройств. То есть жесткие IDE-диски как были устройствами вида /dev/ad#
, так ими и остались. Не превратившись в жутких монстров вроде /dev/ide/...
, что вынуждено произошло в Linux.
Второе отличие devfs во Free от ее Linux'овой ипостаси - возможность полностью игнорировать пресловутую "обратную совместимость". В Linux это также вынужденная мера, рассчитанная на программы (низкоуровневые утилиты), которые о devfs не подозревают. А во FreeBSD такой нужды почти не возникает - все программы, напрямую работающие с устройствами, являются неотъемлемой частью операционной системы (к вопросу о преимуществах централизованной разработки).
Однако и обеспечить обратную совместимость, в случае потребности в ней, никто не запрещает. Так, многие мультимедийные приложения из портов FreeBSD (типичный пример - знаменитый mplayer
) при проигрывании компакт-дисков или VideoCD желают, чтобы соответствующее устройство носило имя /dev/cdrom
. Во Free же по умолчанию такого устройства нету - привод компакт-дисков именуется /dev/acd0
(или /dev/acd1
).
Очевидно, что стандартное решение такого рода проблем - создание символической ссылки /dev/cdrom
-> /dev/acd0
, - тут не подходит: содержимое каталога /dev
полностью переписывается при рестарте системы, и, следовательно, такая ссылка будет существовать только в текущем сеансе (а создавать ее каждый раз заново - конечно же, лениво).
Проблема обходится легко - редактированием файла /etc/devfs.conf
, задающего конфигурацию демона "обратной совместимости" файловой системы устройств - devd
. Достаточно внести в этот файл строку вида
link acd0 cdrom
чтобы соответствующая ссылка (/dev/cdrom
-> /dev/acd0
) образовывалась нечувствительно для порльзователя, при старте системы.
Mfs
Файловая система MFS представляет собой частный случай более широкого явления - механизма memory disks, через который осуществляется также поддержка виртуальных дисков в оперативной памяти (аналог RAM-дисков в DOS и Linux) и доступ к файлам (например, iso-образам CD-дисков) как к реальным устройствам (аналог loopback-устройств в Linux). Однако в этой заметке мы ограничимся только рассмотрением собственно mfs - о RAM-дисках я смогу рассказать, когда у меня дойдут до них руки, а обращение с файлами как устройствами рассмотрено при описании процесса записи CD-R/RW.
Назначение mfs - заменить собой дисковые устройства там, где требуется быстрая, но не обязательно долговременная, запись. То есть - для всякого рода промежуточных каталогов при архивации/разархивации, пакетной конвертации графических файлов, а также компиляции программ.
Наиболее целесообразно использовать mfs для монтирования в каталог типа /tmp
, предназначенныйq для хранения всякого рода временных файлов, а также периодически задействовать ее под каталог /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 Гбайт памяти и swap-разделом в 2 Гбайт) в среднем за 23 минуты, с использованием mfs в качестве временнойго хранилища (512 Мбайт) - за 21 минуту. То есть выигрышь от использования mfs действительно составляет менее 10%. Много это или мало - каждый может решить для себя, но ведь, что характерно - в любом случае этот прирост достается абсолютно задарма.
Однако монтирование mfs в /usr/obj
имеет еще и побочный, но полезный эффект - отпадает необходимость в выполнении операций типа make clean
для очистки дерева исходников от промежуточных продуктов компиляции: перестройка "мира" и ядра при этом каждый раз будет выполняться с "чистого листа". Тоже вроде пустяк, но ведь невредно, и усилий не требует ни малейших. Да и забыть про 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
еще и noatime
- просто сам бог велел.
Остается решить, сколько памяти отдать на растерзание 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
). Это при том, что мой "мир" собирался чуть ли не в минимальной конфигурации - практически все, что можно запретить в /etc/make.conf
, было запрещено. Так что, похоже, 512 Мбайт - необходимый минимум для mfs в /usr/obj
.
Очевидно, что даже при гигабайтном ОЗУ отвести такое его количество под mfs на постоянной основе - излишество нехорошее. Так что лучше монтировать файловую систему /usr/obj
только по мере надобности - непосредственно перед пересборкой "мира" и ядра:
$ mdmfs -S -o async -s 512m md1 /usr/obj
размонтируя ее по завершении (впрочем, пересборка ядра все равно потребует перезагрузки, и mfs в /usr/obj
пропадет естественным образом).
Очень важное предупреждение: современная схема тотальной "перестройки мира", включающая make builworld
и make buildkernel
с их последующей инсталляцией, требует обязательного рестарта системы (а не просто перехода в однопользовательский режим) перед выполнением операции make installworld
.
Очевидно, что при этом прибегать к монтированию mfs в /usr/obj
нельзя - ведь при этом после перезагрузки нам, собственно, нечего будет инсталлировать. Что существенно сужает сферу применимости mfs - только для пересборки ядра. Однако ранее (по версию 5.1 включительно) описанная схема проходила, и не исключено, что в будущем ситуация опять изменится.
Кое-что о своппинге
В предыдущих заметках неоднократно, но между делом упоминалось о разделах для своппинга - пора уделить этому несколько слов специально. Поскольку на самостоятельный раздел этот рассказ не тянет, лучшего места, чем в повествовании про виртуальные файловые системы, я для этого не придумал. Ведь своппинг имеет непосредственное отношение к виртуальной памяти.
Что такое своппинг - знают, наверное, все. Это способ увеличения доступного ОЗУ путем переноса редко используемых данных из оперативной памяти на диск и извлечения их обратно по мере необходимости. Для чего на диске создается либо специальный раздел, либо - просто отдельный файл подкачки.
Во FreeBSD принято задействовать под своппинг отдельную партицию в BSD-слайсе. Хотя можно отдать на это благое дело и слайс целиком - в таком случае открываются перспективы совместного использования своп-пространства FreeBSD и другими ОС, например, Linux. А об использовании своп-файла можно прочитать здесь.
Обычно (это и настоятельная рекомендация, и одно из умолчаний sysinstall
) под раздел подкачки отводится объем дискового пространства, равный удвоенному объему ОЗУ. Не испытывая обычно напряженки с емкостью дисков, я всегда следовал этому правилу. Хотя при обычных нынче объемах памяти система устанавливается, грузится и работает без проблем.
Тем не менее, экономия на swap-пространстве не оправданна. FreeBSD работает с ним иначе, чем, например, Linux (и, насколько я понимаю, иначе, чем Windows). В раздел подкачки данные из памяти перемещаются не по заполнении ее - своппингу подвергаются страницы памяти, к которым давно не было обращений. И потому, вне зависимости от того, сколько имеется оперативной памяти и насколько она загружена, некий минимум занятого своп-пространства будет практически всегда. Собственно говоря, соотношение RAM и swap во FreeBSD подобно соотношению процессорного кэша и оперативной памяти: в наиболее быстродйствующей части виртуальной памяти содержатся только самые востребованные в настоящий момент данные.
В этом легко можно убедиться с помощью команды top
. Так, на машине, на которой пишется эта заметка, в данный момент загружен в консоли только редактор vim (не то чтобы это обычное использование моей тачки - я выгрузил все остальное специально, эксперимента ради). Однако в выводе top
можно видеть, что при гигабайте общей памяти, из которой свободно более 900 Мбайт, объем занятого свопа составляет примерно 150 Кбайт. При большом же количестве загруженных приложений раздел подкачки будет задействован более интенсивно - для того, чтобы предоставить максимум памяти активным на текущий момент задачам.
Также не встречалось мне в документации и упоминаний о верхнем ограничении на объем swap-раздела (подобно тому, как в Linux для архитектуры PC он ограничен ныне двумя гигабайтами). Можно предполагать, что такое ограничение теоретически существует, однако, учитываю внутреннюю 64-разрядность FreeBSD (начиная с 5-й ветки), оно лежит, видимо, далеко за пределами практически достижимого.
Раздел для своппинга обычно создается в ходе первичной установки FreeBSD. Собственно, при установке ее через sysinstall
раньше без него обойтись и не удавалось - если в ходе разметки диска отказаться от создания раздела подкачки, следовало сообщение об ошибке. Правда, начиная с версии 5.2.1, вместо него выводится лишь предупреждение - если памяти окажется недостаточно, инсталляция будет прервана.
Однако разделы эти можно создавать и в последующем, например, при подключении нового диска: разнесение области подкачки на два раздела, лежащих на подключенных к разным IDE-каналам дисках, весьма, как говорят, способствует производительности (хотя если диски сидят на одном канале, быстродействие обмена память-своппинг не только не возрастет, но, скорее всего, снизится).
Количество разделов подкачки определяется соответствующей опцией при конфигурировании ядра (по умолчанию в GENERIC не задействована). Если придать ей значение большее, чем разделов имеется в реальности, системой резервируется некоторое пространство для этого. Впрочем, в документации к ядру чрезмерно увлекаться таким резервированием не советуют.
Создать swap-раздел можно или через тот же sysinstall
, или - вручную, причем последнее - не менее просто: достаточно вызвать программу
$ bsdlabel -e /dev/ad#
и в соответствие с описанным в посвященном тому разделе форматом внести туда запись о партиции, которой необходимо только придать литеру b
в качестве обозначения и определить swap
в качестве fstype
(не забыв, конечно, про оффсет и размер). Никаких файловых систем на swap-разделе создавать не нужно (их на нем и нет). Не требуется также команд типа mkswap
, как в Linux: swap-раздел готов к использованию сразу после его разметки.
Единственное, что еще нужно - активизировать раздел подкачки. Это делается командой
$ swapon /dev/имя_партиции
Та же команда без аргумента, но с указанием опции -a
, активизирует все разделы подкачки, записи для которых имеются в файле /etc/fstab
. Обратные действия - деактивация своп-раздела или разделов, - осуществляются командами
$ swapoff /dev/имя_партиции
для единичного устройства, или
$ swapoff -a
для всех swap-устройств из /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'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
А теперь - на второй:
$ 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-разделы занимают стратегически наиболее выгодные (с точки зрения быстродействия) позиции.