A6. Файлова система через FUSE
Кожна файлова система зводиться до кількох структур на диску: суперблок,
бітові карти, таблиця inode, блоки даних. Модуль 15
описує їх і пояснює, чому ім’я файлу живе в каталозі, а не в inode.
У цій роботі ви реалізуєте ці структури самі, змонтуєте результат
через FUSE і перевірите його звичайними ls, cat і ln. Після цього
жорсткі посилання перестають бути дивиною: це другий запис у каталозі
з тим самим номером inode. FUSE працює в режимі користувача, тож помилка
завершить лише вашу програму, система встоїть.
Після цієї роботи ви зможете:
- розкласти образ файлової системи на суперблок, бітові карти, таблицю inode і блоки даних і пояснити, за що відповідає кожна ділянка;
- реалізувати обробники FUSE так, щоб
ls,cat,mkdir,lnіrmпрацювали з вашим форматом без жодних змін у цих утилітах; - пояснити, чому
unlinkне знищує дані, поки лічильник посилань не дійшов до нуля, і показати це на власній ФС черезstatдвох імен; - перевірити, що стан ФС переживає відмонтування, і знайти те, що трималося лише в пам’яті.
У роботі це трапляється, коли після обриву живлення fsck перевіряє
ті самі лічильники й бітові карти, або коли ви монтуєте sshfs
чи хмарне сховище: вони зроблені на тому самому FUSE.
Завдання
Section titled “Завдання”Написати дві програми: mkfs.myfs, яка створює порожню файлову систему
у файлі-образі, і myfs, яка монтує цей образ через FUSE.
./mkfs.myfs disk.img 64M # створити порожню ФС у файлі./myfs disk.img /mnt/my # змонтуватиfusermount3 -u /mnt/my # відмонтуватиЩо має вміти:
mkfs.myfsзаписує суперблок, обнуляє бітові карти і створює кореневий каталог із записами.і..;- після монтування всередині працюють
mkdir,touch,echo > file,cat,ls -l,ln,rm,stat; - файли читаються назад і мають правильний розмір у
stat; файл на 100 КБ записується цілком; rmdirвідмовляє на непорожньому каталозі і видаляє порожній;- жорсткі посилання:
lnдає друге ім’я з тим самим номером inode і лічильником 2; після видалення першого імені дані читаються за другим, а лічильник стає 1; - блоки повертаються у вільні після видалення файлу, і
dfна точці монтування це показує (обробникstatfs); - усе перелічене переживає відмонтування й повторне монтування.
Чого робити не треба. Непрямі блоки й журнал винесені в «Далі,
якщо цікаво». Символьні посилання, перейменування і права доступу
автоперевірка не використовує. Тримати відкритий файл із нульовим
nlink живим до закриття не обов’язково, але про це є пункт у звіті.
Обмеження. libfuse бере на себе лише обмін із ядром; розбір шляхів, записи каталогів, бітові карти і зростання файлу пишете самі за форматом нижче.
Що записати у звіт:
- що станеться у вашій ФС, якщо видалити файл, який хтось тримає відкритим (див. Aside після етапів);
- максимальний розмір файлу, який допускає ваш формат, і що його обмежує;
- кількість вільних блоків до і після ста створень і видалень файлу;
- що не пережило перемонтування з першого разу і де воно трималося лише в пам’яті.
Готово, коли:
./check.sh ./myfs ./mkfs.myfsпроходить усі двадцять одну перевірку в шести групах; якщоdfне бачить вільного місця, перевірку звільнення скрипт пропускає, і їх лишається двадцять;- образ, створений
mkfs.myfs, монтується вдруге з усіма файлами й посиланнями на місці; - у звіті є чотири пункти вище.
Перед початком
Section titled “Перед початком”- Прочитайте в модулі 15 розділи «inode», «Розподіл блоків» і «overlayfs і FUSE».
- Потрібен пристрій
/dev/fuse, якого в непривілейованому контейнері немає (чому). Беріть віртуальну машину або WSL2. У Vagrant-машині з архіву вже стоятьlibfuse3-devіfuse3; на своїй системі їх поставитьsetup/provision.sh. - Розпакуйте архів курсу: перевірка лежить
у
labs/a6-filesystem/check.sh. Їй потрібніfusermount3(абоfusermount) іmountpoint; на монтування вона дає 10 секунд. Опис обробників є уfuse3/fuse.h, структураfuse_operations.
Формат на диску
Section titled “Формат на диску”Мінімальний, але справжній:
| Ділянка | Що містить |
|---|---|
| Суперблок | сигнатура, розмір блока, кількість inode і блоків, зміщення решти ділянок |
| Бітова карта inode | по біту на inode: зайнятий чи ні |
| Бітова карта блоків | по біту на блок даних |
| Таблиця inode | тип, права, розмір, лічильник посилань, часи, вказівники на блоки |
| Блоки даних | вміст файлів і записи каталогів |
Каталог зберігається як звичайний файл, вміст якого є послідовністю записів «довжина імені, номер inode, ім’я».
-
mkfs. Створити образ, записати суперблок, обнулити бітові карти, створити кореневий каталог із записами.і... -
Монтування й читання. Реалізувати
getattr,readdir,open,read. На цьому етапі ФС уже видно вls, хоч записувати ще не можна.getattrнайважливіша з них: без неї не працює нічого, і на ній зазвичай застрягають. -
Запис.
create,write,truncate,unlink. Тут з’являється робота з бітовою картою блоків і зростання файлу. -
Каталоги.
mkdir,rmdir.rmdirмає відмовляти на непорожньому каталозі; переконайтеся, що ваша перевірка не рахує.і... -
Жорсткі посилання.
linkзбільшує лічильник,unlinkзменшує; inode звільняється лише на нулі.Обов’язкова перевірка: створити файл, зробити на нього посилання, видалити оригінал, прочитати за другим іменем. Дані мають бути на місці.
-
Стійкість до перезапуску. Відмонтуйте, змонтуйте знову, переконайтеся, що все на місці. Якщо ні, значить, ви щось тримали лише в пам’яті.
Автоперевірка
Section titled “Автоперевірка”Перевірка лежить в архіві з файлами курсу, і команди нижче виконуються з розпакованого каталогу.
cd labs/a6-filesystem./check.sh ./myfs ./mkfs.myfsСкрипт створює образ, монтує його у тимчасовий каталог, проганяє сценарії з файлами, каталогами й посиланнями, відмонтовує й монтує знову, щоб перевірити збереження стану.
Часті помилки
Section titled “Часті помилки”Жорсткі посилання «не працюють», хоча код правильний. Найдорожча
пастка цієї роботи, і вона не у вашому коді. За замовчуванням libfuse
підставляє власні номери inode замість тих, що ви повертаєте
з getattr, і кешує атрибути на секунду. Тому stat показує два різні
inode для двох імен одного файлу й застарілий nlink.
Лікується обробником init:
static void *fs_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { cfg->use_ino = 1; // брати st_ino з нашого getattr cfg->attr_timeout = 0; // не кешувати атрибути cfg->entry_timeout = 0; return NULL;}Кеш можна лишити ввімкненим у готовій ФС, але поки ви її налагоджуєте, він приховує половину помилок.
getattr повертає неправильний розмір. Тоді cat читає зайве або
обрізає файл. Розмір беруть з inode; кількість блоків його не визначає.
Каталог не має . і ... На них розраховує чимало утиліт, тож ls
почне поводитися дивно.
Блоки не звільняються. Місце тікатиме при кожному видаленні. Перевірити просто: створіть і видаліть файл сто разів, а потім подивіться на вільні блоки.
Немає перевірки меж. Ім’я, довше за максимальне, або запис за межу файлу зіпсують сусідні структури. Це та сама помилка, що й у A4, тільки на диску.
Далі, якщо цікаво
Section titled “Далі, якщо цікаво”Додати непрямі блоки й подивитися, як зростає максимальний розмір файлу (модуль 15). Або додати журнал і перевірити, що ФС переживає обрив на середині запису.