Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 122, ФЕВРАЛЬ 2009 г.

Побег за пределы ядра. Обзор файловых систем, основанных на fuse

Евгений «j1m» Зобнин (zobnin@gmail.com)




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

Бред увлекшегося гения

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

Вскоре появились также именованные каналы, сокеты и файловая система /proc. Идея оказалась столь удачной, что в Plan9 он сделал файлы логическим центром всей операционной системы – представлено ими было абсолютно все: графическая оконная система, сокеты, http- или dns-запросы. Хоть это и похоже на бред увлекшегося гения, такой подход сделал операционку простой, чрезвычайно гибкой и легкой в освоении. Пользователь мог выполнить практически любую задачу с помощью стандартных инструментов, манипулирующих файлами и каталогами. Для общения в irc, навигации по ftp и даже работы с блогом не требовалось специальных программ, как не требовалось тратить время на их изучение. Все можно было сделать с помощью стандартных консольных команд или файлового менеджера.

Частичка микроядерности в монолитном ядре

Технология fuse не так красива, как протокол 9P из Plan9, но, все же, прекрасно справляется со своими задачами. По сути, fuse - способ вынести файловую систему в пространство пользователя. Это специальный модуль ядра, который позволяет написать файловую систему буквально на коленке, не вникая в подробности ядерного кодинга. Благодаря тому, что файловая система, основанная на fuse, работает в юзерспейс, программист может представить как файловое дерево практически все, не нарушая целостности ядра и не создавая огромных дыр в безопасности. Интерфейс fuse - это своего рода частичка микроядерности в монолитном ядре.
Писать файловые системы на основе fuse действительно просто, иногда даже проще, чем обычные программы. Наверное, именно поэтому для fuse с 2005 года создано более сотни файловых систем.

Установка

Подавляющее большинство дистрибутивов Linux уже подготовлены для работы файловых систем, основанных на fuse. Поэтому пингвиноводам достаточно установить пакеты libfuse и libfuse-devel, если они еще не установлены. В FreeBSD модуль fuse и большинство рассматриваемых в статье файловых систем доступны через порты (sysutils/fusefs-*). Чтобы дать привилегии монтирования этих ФС обычным пользователям, придется подправить значение специальной переменной sysctl:

# sysctl vfs.usermount=1
# echo 'vfs.usermount=1' >> /etc/sysctl.conf

Во FreeBSD нет порта, устанавливающего команду fusermount, и для демонтирования файловых систем нужно использовать стандартную команду umount.

Компрессия

У кого как, а у меня всегда был пунктик по поводу отсутствия прозрачной компрессии в стандартных файловых системах Linux и BSD. Дело не в том, что я слишком жадный, чтобы купить новый жесткий диск. Я отдаю предпочтение производительности, а не свободному пространству!

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

Для fuse существует несколько реализаций файловых систем с прозрачным сжатием/распаковкой данных. Одни из них работают с обычными архивами, другие – сжимают данные поблочно. К первым относится файловая система fuse-zip (code.google.com/p/fuse-zip), позволяющая на лету читать или добавлять файлы в zip-архивы. Она отлично справляется с небольшими архивами и хорошо подходит, например, для сжатия корня файловой системы. Пользоваться ей очень просто:

$ mkdir /tmp/zip
$ fuse-zip /tmp/arch.zip /tmp/zip

В случае, если архив не существует, он будет создан. К сожалению, fuse-zip для больших массивов данных не подходит. Она быстра, удобна и достаточно стабильна, но хранит распакованное содержимое архива в оперативной памяти, поэтому, когда размер архива станет больше объема установленной памяти, в дело вступит раздел подкачки, и система начнет дико тормозить. Самое страшное, что после того, как пространство на разделе подкачки иссякнет, дальнейшее поведение файловой системы непредсказуемо (у меня, например, она оказалась в нокауте). Именно поэтому для сжатия больших файловых архивов лучше использовать ФС с поблочным шифрованием. CompFUSEd (www.biggerbytes.be) - лучшее решение в данной области для fuse. Она поддерживает несколько алгоритмов сжатия (gzip, bzip2, lzo, lzo2) и работает с небольшими блоками данных (8-64 Кб), поэтому почти не кушает оперативную память. Единственный недостаток – в способе установке, который не предполагает никакого автоконфигурирования и автоматизированной инсталляции. Придется делать это ручками:

$ cd /tmp
$ tar xzf cf-GISMO-200712321.tgz
$ cd ./CompFused/Gismo/
$ make
# cp cf_main /usr/local/bin/compFUSEd
# mkdir /usr/local/lib/compFUSEd/
# cp -av plugins /usr/local/lib/compFUSEd

Создаем конфигурационный файл ~/.compFUSEd и пишем в него:

$ vim ~/.compFUSEd

[/home/vasya/compressed]
# Здесь будут храниться сжатые файлы
backend = /home/vasya/.compressed
# Способ компрессии (cf_zlib.so, cf_bzip2.so, cf_lzo.so или cf_lzo2.so)
compression = /usr/local/lib/compFUSEd/plugins/cf_lzo2.so
writer = /usr/local/lib/compFUSEd/plugins/writer_smarter.so
# Размер блока
chunk_size = 65553
# Максимальное количество блоков в одном файле
chunk_max = 100
# Не сжимать файлы следующих типов
exclude = gz tgz bz2 tbz2 zip rar jpeg avi mp3

Подключаем файловую систему:

$ compFUSEd ~/compressed

Все файлы, помещенные в каталог ~/compressed, теперь будут автоматически сжиматься и помещаться в ~/.compressed. Если ты захочешь подключить compFUSEd к системному каталогу, такому как /usr/src, то конфигурационный файл следует поместить в /usr/local/etc под именем compFUSEed.conf.

На самом деле, CompFUSEd не так быстра, как хотелось бы. Сказываются простои при копировании данных из ядра в юзерспейс и обратно. Для достижения максимальной производительности лучше применить «настоящие» файловые системы с прозрачным сжатием, такие как Reiser4 в Linux или ZFS во FreeBSD.

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

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

Начнем с излюбленного инструмента системного администратора - ssh. Модуль sshfs (fuse.sourceforge.net/sshfs.html), реализованный поверх протокола sftp, способен представить ssh-соединение в виде файлового дерева. Использовать его так же просто, как и все остальные ФС на базе fuse:

$ sshfs user@example.com точка_монтирования

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

Теперь о старом добром ftp: лучшее, что есть на эту тему для fuse, называется curlftpfs (curlftpfs.sourceforge.net). Она основана на библиотеке libcurl, поэтому поддерживает ssl-шифрование, http-прокси и автоматическое восстановление связи. Это действительно удобный и полезный инструмент, с помощью которого можно, например, примонтировать ftp-архив дистфайлов FreeBSD к каталогу /usr/ports/distfiles и забыть о выделении свободного места для них:

# curlftpfs ftp://ftp.freebsd.org/pub/FreeBSD/ports/distfiles /usr/ports/distfiles

Для fuse также существует реализация файловой системы http (httpfs.sourceforge.net), но особого интереса она не представляет. Совсем другое дело - smbnetfs (smbnetfs.sourceforge.net), основанная на библиотеке smbclient. Она монтирует расшаренные ресурсы пользователей Windows или сервера Samba. Для ее использования необходимо создать каталог ~/.smb и поместить в него файлы smb.conf и smbnetfs.conf. Первый можно взять из каталога /etc или /usr/local/etc, но для этого потребуется установить пакет Samba. Второй берется из дистрибутивного файла smbnetfs, и менять в нем ничего не нужно. После выполнения этих действий создадим точку монтирования и примонтируем к ней smbnetfs:

$ mkdir -p ~/mnt/smb
$ smbnetfs ~/mnt/smb

Теперь, чтобы увидеть все рабочие группы, существующие в сети, набирай «cd ~/mnt/smb». А чтобы обратиться к любому хосту по его IP-адресу:

$ cd ~/mnt/smb/ip-адрес

Либо:

$ cd ~/mnt/smb/пользователь:пароль@хост

Шифрование

Для fuse существует несколько реализаций шифрующих файловых систем. Среди них есть и бриллиант под названием encfs (www.arg0.net/encfs). В отличие от других подобных разработок, encfs работает поверх существующей файловой системы, а не шифрует данные на уровне блочного устройства. Такой подход обладает сразу несколькими преимуществами. Это и динамический рост файловой системы по мере накопления данных; дружелюбность к системам бэкапа, которые правильно могут определить, какие конкретно файлы подверглись модификации; возможность шифрования другой виртуальной файловой системы (например, ты можешь подключить curlftpfs, создать каталог, подключить к нему encfs, и все заливаемые в него данные сохранятся на сервере в зашифрованном виде). К минусам можно отнести тот факт, что злоумышленник способен узнать все о структуре зашифрованной файловой системы, включая количество файлов и каталогов, их размер и время модификации. Загадкой для него останутся только их имена и содержимое. Чтобы начать использовать encfs, создадим два пустых каталога:

$ cd /tmp
$ mkdir crypted decrypted

И подключим к ним encfs:

$ encfs /tmp/crypted /tmp/decrypted

На вопрос о режиме настройки ответим нажатием 'p'. Тогда encfs, использующая библиотеку ssl, сама выберет самый надежный метод шифрования, и нам останется только ввести пароль к каталогу. С другой стороны, можно нажать 'x' и самостоятельно выбрать алгоритм шифрования, длину ключа и другие параметры. Переходим в каталог /tmp/decrypted и добавляем в него файл:

$ cd decrypted
$ echo "secret" > file

После этого encfs можно отключить и посмотреть результат:

$ fusermount -u /tmp/decrypted
$ cd /tmp/crypted
$ ls

Вкусности

В этом разделе речь пойдет о необычных файловых системах, которые могут быть полезны. Среди самой разной экзотики я отобрал трех претендентов: goofs, offlinefs и powfs.

Файловая система goofs (code.google.com/p/goofs) предназначена для работы с различными сервисами Google, такими как:

  1. Календарь - добавление, удаление и поиск событий.
  2. Picasa - добавление и удаление фотографий и альбомов.
  3. Контакты - создание, удаление и изменение.
  4. Blogger - создание, удаление и изменение постов и комментариев.
  5. Документы - добавление и удаление документов.

Goofs написана на python, поэтому требует пакеты python-fuse (fuse.sourceforge.net/wiki/index.php/FusePython) и python-gdata (code.google.com/p/gdata-python-client/). Благо, они доступны в портах FreeBSD и репозитариях всех популярных дистрибутивов Linux. Для запуска goofs выполняем последовательность действий:

$ tar -xzf goofs-0.6.tar.gz
$ cd goofs/src/goofs
$ mkdir -p ~/mnt/google
$ python goofs.py ~/mnt/google --user zobnin@gmail.com --pw password

Как итог, в каталоге ~/mnt/google появится несколько подкаталогов, имена которых соответствуют определенным сервисам. Структура их логична и интуитивно понятна. Для примера опишу работу с сервисом blogger.com. Заходим в сервис:

$ cd ~/mnt/google/blogs

Переходим к одному из блогов:

$ cd "Мой блог, который я забываю пополнять"

Добавляем новый пост:

$ mkdir "Мне не нужен браузер, чтобы писать в блог"

И – наполняем его содержанием:

$ cd "Мне не нужен браузер, чтобы писать в блог"
$ echo "Теперь у меня есть goofs" > content

Оставляем комментарий:

$ cd comments
$ echo "Почему не комментируем? Где все?" > new

Удобно, не правда ли? При этом посты можно удалять, переименовывать, изменять содержание, копировать посты из другого каталога. Вооружившись /bin/sh, ты легко создашь скрипт, который по cron'у будет добавлять важные данные в блог. Даешь мониторинг сервера через блог! Единственное ограничение - UTF-8. Goofs, как и все сервисы Google, использует UTF-8 и только ее. Придется отказаться от локали KOI8-R, чтобы работать с удобством.

Вторая файловая система из нашего списка - offlinefs (savannah.nongnu.org/projects/offlinefs) - предназначена для организации коллекций на CD/DVD-дисках и других носителях. Она хранит не файлы, а специальные базы данных, с помощью которых создает иллюзию нахождения этих файлов на диске. Допустим, у тебя есть огромная коллекция дисков с записанными фильмами. Offlinefs сделает так, как будто все эти фильмы лежат у тебя на жестком диске. Ты можешь их сортировать, переименовывать, но при попытке получить доступ к одному из них, ФС попросит вставить диск с определенной меткой. Создаем базу (она будет размещена в каталоге ~/.offlinefs) и монтируем:

$ offlinefs --rebuilddb
$ offlinefs ~/куча_всего

Вставляем диск и добавляем его в базу:

$ offimport_cd.sh -i /mnt/cdrom -l "фильмы-1"

Поздравляю, содержимое диска теперь доступно через каталог ~/куча_всего. Ну и, наконец, powfs (powfs.sourceforge.net) - простая файловая система, извещающая об изменении файлов. Если какой-либо из файлов, находящихся в каталоге, на который «натравлена» powfs, изменится, – будет запущен указанный скрипт: что-то вроде механизма inotify, но не в ядре и гораздо проще. Использовать так –

# vim ~/.powfs

handler.dir.0=/tmp
handler.prg.0=/usr/local/bin/script1.sh
handler.dir.1=/etc
handler.prg.1=/usr/local/bin/script2.sh

Монтируем:

$ powfs ~/не_изменять

Если внутри каталога ~/не_изменять/tmp изменится файл, будет запущен script1.sh, в ~/не_изменять/etc - script2.sh (пути, указанные в ~/.powfs, являются абсолютными только по отношению к точке монтирования). Внутрь скрипта можно добавить что-то вроде:

mail -s "Изменен файл" root@localhost $1

Автомонтирование

Одно из самых больших неудобств использования файловых систем, основанных на fuse, заключается в необходимости вводить команды монтирования каждый раз перед их использованием. По этой причине большинство пользователей отказываются от fuse в пользу более привычных файловых менеджеров с поддержкой просмотра архивов и подключения к ftp- и ssh-сервисам. К счастью, эта проблема решаема с помощью afuse (afuse.sourceforge.net) - автомаунтера для fuse, представленного как отдельная виртуальная файловая система. В отличие от других решений, он работает в пространстве пользователя и позволяет работать с виртуальными точками монтирования (создавать их по запросу), что незаменимо во время использования sshfs или curlfstpfs. Использовать его следует так:

$ mkdir -p ~/mnt/ssh
$ afuse -o mount_template="sshfs %r:/ %m" -o unmount_template="fusermount -u -z %m" ~/mnt/ssh/

Здесь ~/mnt/ssh - это метакаталог для всех точек монтирования sshfs. После перехода в один из его подкаталогов afuse автоматически выполнит команду монтирования, и мы окажемся внутри нужной машины. Можешь поэкспериментировать, введя «cd ~/mnt/ssh/host.ru». После этого afuse должна выполнить команду, прописанную в аргументе mount_template, и ты окажешься на машине host.ru. Обрати внимание, что специальные модификаторы '%r' и '%m' определяют имена удаленного и локального каталогов, то есть источника и точки монтирования. Причем первый, по сути, генерируется из второго. Кроме того, в обязательном порядке следует настроить авторизацию на основе ключей, потому что afuse не позволяет использовать какое-либо интерактивное взаимодействие.

DVD

На прилагаемом к журналу диске ты найдешь все модули fuse, описанные в статье.

INFO

Модуль fuse - часть древней программы avfs, которая позволяла ходить по ssh-, ftp-, http-ресурсам, различным типам архивов и дистрибутивным пакетам (rpm, deb). Проект давным-давно закрыт, но реализация модуля fuse оказалась настолько удачной, что зажила собственной жизнью.

Содержание
ttfb: 6.1209201812744 ms