Періодично, з метою переїзду в ЦРС співбесідуюсь у різних великих компаніях, переважно Пітера та Москви на посаду DevOps. Звернув увагу, що у багатьох компаніях (у багатьох хороших компаніях, наприклад в яндексі) ставлять два подібні питання:
- що таке inode;
- з яких причин можна отримати помилку запису на диск (або наприклад: чому може закінчитися місце на диску, одна суть).
Як часто буває, я був певен, що цю тему знаю добре, але щойно почав пояснювати — позначилися провали у знаннях. Щоб систематизувати свої знання, заповнити прогалини і більше не ганьбитися, пишу цю статтю, може ще комусь стане в нагоді.
Почну «знизу», тобто. з жорсткого диска (флешки, SSD та інші сучасні штуки відкинемо, наприклад розглянемо будь-який 20 або 80 гіговий старий диск, тому там розмір блоку 512 байт).
Жорсткий диск не вміє адресувати свій простір побайтно, умовно він розбитий на блоки. Нумерація блоків починається з 0. (називається це LBA, подробиці тут:
Як бачимо з малюнка, блоки LBA я позначив як рівень HDD. До речі, подивитися, який розмір блоку вашого диска можна так:
root@ubuntu:/home/serp# blockdev --getpbsz /dev/sdb
512
Рівнем вище розмічений розділ, один на весь диск (знов-таки для простоти). Найчастіше використовують розмітку розділів двох типів: msdos та gpt. Відповідно msdos – старий формат, що підтримує диски до 2Tb, gpt – новий формат, здатний адресувати до 1 зеттабайта 512 байтних блоків. У нашому випадку маємо розділ типу msdos, як видно з малюнка, розділ при цьому починається з блоку №1, а нульовий використовується для MBR.
У першому розділі я створив файлову систему ext2, за замовчуванням розмір блоку має 4096 байт, що також відображено на малюнку. Подивитися розмір блоку файлової системи можна так:
root@ubuntu:/home/serp# tune2fs -l /dev/sdb1
tune2fs 1.42.9 (4-Feb-2014)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: a600bf40-f660-41f6-a3e6-96c303995479
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: ext_attr resize_inode dir_index filetype sparse_super large_file
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 65536
Block count: 261888
Reserved block count: 13094
Free blocks: 257445
Free inodes: 65525
First block: 0
Block size: 4096
Fragment size: 4096
Reserved GDT blocks: 63
Blocks per group: 32768
Fragments per group: 32768
Inodes per group: 8192
Inode blocks per group: 512
Filesystem created: Fri Aug 2 15:02:13 2019
Last mount time: n/a
Last write time: Fri Aug 2 15:02:14 2019
Mount count: 0
Maximum mount count: -1
Last checked: Fri Aug 2 15:02:13 2019
Check interval: 0 (<none>)
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 11
Inode size: 256
Required extra isize: 28
Desired extra isize: 28
Default directory hash: half_md4
Directory Hash Seed: c0155456-ad7d-421f-afd1-c898746ccd76
Потрібний нам параметр - "Block size".
Тепер найцікавіше, як прочитати файл /home/serp/testfile? Файл складається з одного або кількох блоків файлової системи, де зберігаються його дані. Знаючи ім'я файлу як його знайти? Які блоки читати?
Ось тут нам і знадобляться inode. У файловій системі ext2fs є "таблиця", в якій міститься інформація по всіх inode. Кількість inode у разі ext2fs задається при створенні файлової системи. Необхідні цифри дивимося параметрі «Inode count» виведення tune2fs, тобто. маємо 65536 XNUMX штук. В inode міститься потрібна нам інформація: список блоків файлової системи для файлу, що шукається. Як знайти номер inode для вказаного файлу?
Відповідність імені та номера inode міститься в директорії, а директорія в ext2fs – це файл особливого типу, тобто. теж має власний номер inode. Щоб розірвати це хибне коло, для кореневої директорії призначили «фіксований» номер inode «2». Дивимося вміст inode за номером 2:
root@ubuntu:/# debugfs /dev/sdb1
debugfs 1.42.9 (4-Feb-2014)
debugfs: stat <2>
Inode: 2 Type: directory Mode: 0755 Flags: 0x0
Generation: 0 Version: 0x00000000:00000002
User: 0 Group: 0 Size: 4096
File ACL: 0 Directory ACL: 0
Links: 3 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x5d43cb51:16b61bcc -- Fri Aug 2 16:34:09 2019
atime: 0x5d43c247:b704301c -- Fri Aug 2 15:55:35 2019
mtime: 0x5d43cb51:16b61bcc -- Fri Aug 2 16:34:09 2019
crtime: 0x5d43b5c6:00000000 -- Fri Aug 2 15:02:14 2019
Size of extra inode fields: 28
BLOCKS:
(0):579
TOTAL: 1
Як видно, потрібна нам директорія міститься в блоці з номером 579. У ній ми знайдемо номер нода для папки home, і так далі ланцюжком, поки в директорії serp не побачимо номер нода для файлу. Якщо раптом комусь захочеться перевірити, чи правильний номер, і чи є там потрібна інформація, це не складно. Робимо:
root@ubuntu:/# dd if=/dev/sdb1 of=/home/serp/dd_image bs=4096 count=1 skip=579
1+0 records in
1+0 records out
4096 bytes (4,1 kB) copied, 0,000184088 s, 22,3 MB/s
root@ubuntu:/# hexdump -c /home/serp/dd_image
У виводі можна прочитати імена файлів у директорії.
Ось я і підійшов до головного питання: «З яких причин може бути помилка запису»?
Звичайно так станеться, якщо не залишиться вільних блоків файлової системи. Що можна зробити в цьому випадку? Крім очевидного «видалити щось непотрібне», слід пам'ятати, що у файлових системах ext2,3 і 4 є така штука, як «Reserved block count». Якщо подивитися у лістингу вище, то у нас таких блоків «13094». Це блоки доступні для запису лише користувачеві root. але якщо потрібно оперативно вирішити питання, як тимчасове рішення можна зробити їх доступними для всіх, у результаті з'явиться трохи вільного місця:
root@ubuntu:/mnt# tune2fs -m 0 /dev/sdb1
tune2fs 1.42.9 (4-Feb-2014)
Setting reserved blocks percentage to 0% (0 blocks)
Тобто. за промовчанням, у вас не доступно для запису 5% дискового простору, і враховуючи обсяги сучасних дисків, це можуть бути сотні гігабайт.
Що ще може бути? Ще можлива ситуація, коли вільні блоки є, а ноди скінчилися. Таке зазвичай трапляється, якщо у файловій системі купа файлів розміром менше розміру блоку файлової системи. Враховуючи, що на 1 файл або директорію витрачається 1 inode, а всього їх маємо (для даної файлової системи) 65536 ситуація більш ніж реальна. Це можна побачити з висновку команди df:
serp@ubuntu:~$ df -hi
Filesystem Inodes IUsed IFree IUse% Mounted on
udev 493K 480 492K 1% /dev
tmpfs 493K 425 493K 1% /run
/dev/xvda1 512K 240K 273K 47% /
none 493K 2 493K 1% /sys/fs/cgroup
none 493K 2 493K 1% /run/lock
none 493K 1 493K 1% /run/shm
none 493K 2 493K 1% /run/user
/dev/xvdc1 320K 4,1K 316K 2% /var
/dev/xvdb1 64K 195 64K 1% /home
/dev/xvdh1 4,0M 3,1M 940K 78% /var/www
serp@ubuntu:~$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 2,0G 4,0K 2,0G 1% /dev
tmpfs 395M 620K 394M 1% /run
/dev/xvda1 7,8G 2,9G 4,6G 39% /
none 4,0K 0 4,0K 0% /sys/fs/cgroup
none 5,0M 0 5,0M 0% /run/lock
none 2,0G 0 2,0G 0% /run/shm
none 100M 0 100M 0% /run/user
/dev/xvdc1 4,8G 2,6G 2,0G 57% /var
/dev/xvdb1 990M 4,0M 919M 1% /home
/dev/xvdh1 63G 35G 25G 59% /var/www
Як добре помітно на розділі /var/www, кількість вільних блоків файлової системи та кількість вільних нодів сильно різниться.
У разі якщо скінчилися inode, заклинань не підкажу, т.к. їх немає (якщо не правий, дайте знати). Так що для розділів у яких розмножуються дрібні файли слід грамотно вибирати файлову систему. Так наприклад, в btrfs іноді не можуть закінчитися, т.к. динамічно створюються нові за необхідності.
Джерело: habr.com