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'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-разделы занимают стратегически наиболее выгодные (с точки зрения быстродействия) позиции.



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

Нашли ошибку на сайте? Выделите текст и нажмите Shift+Enter

Код для блога бета

Выделите HTML-код в поле, скопируйте его в буфер и вставьте в свой блог.