/FUSE-LZ4

Experimentation with fuselib -- implementing LZ4 data compression on the filesystem

Primary LanguageC

FUSE-LZ4

Учебный проект по курсу ОС университета ИТМО магистратуры JetBrains.

Автор работы: Крыштапович Виктор.

Описание

FUSE является библиотекой Linux для реализации файловых систем в пространстве имён пользователя (user namespace). Проект предназначен для ОС Linux, в частности, для Ubuntu 18.04, но может быть запущен и на других дистрибутивах Linux с большой вероятностью.

Зависимости

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

sudo apt-get install libfuse-dev

По крайней мере именно такая зависимость позволила скомпилировать проект с FUSE на ОС Ubuntu 18.04.

Помимо этого, необходимо скачать исходники lz4 (см. ссылку 3) и использовать их при компиляции проекта.

Сборка

Для сборки проекта предусмотрен простенький makefile, который позволяет собрать файловую систему с помощью команды make. В этом случае появится исполняемый файл fuse-lz4.fs, который и представляет из себя пользовательскую файловую систему, которую можно смонтировать в желаемое место. Для очистки сборки используйте make clean. Для сборки потребуется компилятор gcc.

За основу взята файловая система из примеров passthough_ll.c, которая дублирует работу файловой системы. Для сборки необходимо наличие файла config.h, в котором перечислена конфигурация операционной системы, т.е. что она умеет.

Примеры:

В makefile можно собрать много чего интересного:

  1. make ssfs -- собирает тупую файловую систему на минималках. Код там несложный
  2. make passthrough -- более продвинутый пример, который собирает приемлимый по производительности вариант файловой системы, зеркалирующий корень файловой системы. Однако это не самый быстрый вариант (есть вариант низкоуровневой реализации на FUSE, либо можно вообще писать на уровне ядра и забыть о FUSE)
  3. make framecompress -- собирает исполняемый файл frameCompress.o, который сжимает файлы с помощью алгоритма lz4 в блочном режиме, также разжимает их и проверяет соответствие сжатого файла оригинальному. Один из кандидатов на встраивание в нашу целевую файловую систему
  4. make fuse_write_substituter -- собирает файловую систему на базе passthough_ll.c, которая уже менее бесполезна, но всё ещё очень бесполезна -- заменяет все записываемые блоки на диск на фамилию и имя автора данного проекта.
  5. Сборка основного проекта fuse-lz4 осуществляется просто командой make, или make build

Таким образом, нетрудно догадаться, что успешное решение задачи заключается в том, чтобы интегрировать реализацию блочного сжатия файлов в п.3 в делегирующую реализацию файловой системы passthrough. Скопируем этот файл в fuse_lz4.c и будем добавлять в него соответствующую реализацию алгоритма сжатия данных.

Запуск

После сборки с помощью make файловая система запускается так:

./fuse-lz4.fs -f mountpoint

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

Таким образом, Запись в файлов в папке mountpoint, к которой примонтирована файловая система, ведёт к их сжатию с помощью LZ4!

Для удобства можно добавить символическую ссылку вглубь mountpoint, которая будет становиться валидной при монтировании файловой системы (жёсткую делать не рекомендуется).

Для размонтирования можно применять следующие команды:

fusermount [OPTIONS] mountpoint

В особо плохих случаях (как в моём, для которого старая схема монтирования не поддерживается):

sudo umount [-f] [-l] mountpoint

TODO

  • Избавиться от реальных и потенциальных багов при компрессии в файловой системе.

Обнаруженные баги

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

Пример работы файловой системы

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

Файл до компрессии (тот, что виден пользователю): FUSE-LZ4 example of file before unpack

Файл после компрессии (тот, что на самом деле хранится на диске): FUSE-LZ4 example of file before unpack

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

Ссылки на источники

  1. https://github.com/libfuse/libfuse
  2. https://github.com/thyu/lz4xx/blob/master/include/lz4.h
  3. https://github.com/lz4/lz4/
  4. https://github.com/gordan-bobic/zfs-fuse
  5. https://www.howtoinstall.co/en/ubuntu/trusty/libfuse-dev
  6. Хороший туториал по написанию простейшей ФС: https://www.maastaar.net/fuse/linux/filesystem/c/2016/05/21/writing-a-simple-filesystem-using-fuse/
  7. Часть два туториала про Simple Stupid File System: https://www.maastaar.net/fuse/linux/filesystem/c/2016/05/21/writing-a-simple-filesystem-using-fuse/
  8. Хороший старт для разрабатываемого кейса находится тут. Это пример файловой системы, которая делегирует все операции стандартной библиотеке libc: https://libfuse.github.io/doxygen/example_2passthrough_8c.html
  9. Отличная статья о LZ4: https://habr.com/en/company/yandex/blog/452778/, но свой LZ4 не будем реализовывать, воспользуемся популярным, упоминаемым в статье (см. п. 3)
  10. https://github.com/acozzette/BUSE -- Это как FUSE, только BUSE. Возможно, с помощью него задача решается легче