Inode-ovi i linkovi — kako sistem zapravo čuva fajl
Ime fajla nije fajl. To je jedna od onih rečenica koje zvuče kao filozofija dok ne naiđeš na situaciju u kojoj si obrisao ogroman log, a disk je i dalje pun. Ili dok ti dva različita imena ne pokažu potpuno isti sadržaj, pa se pitaš gde je greška.
Greške nema. Linux fajl i ime fajla drži razdvojeno, a spona između njih zove se inode. Kad razumeš tu podelu, hard i simbolički linkovi prestaju da budu magija, a nekoliko čestih administratorskih problema dobija očigledno rešenje.
Šta je inode
Kad se fajl upiše na disk, sistem napravi zapis koji sadrži sve o tom fajlu osim imena:
- tip fajla i dozvole
- vlasnika i grupu
- veličinu
- vremenske oznake
- broj imena koja pokazuju na njega
- adrese blokova na disku gde je sadržaj
Taj zapis je inode i ima svoj broj. Vidiš ga sa ls -i:
$ ls -li 1310721 -rw-r--r-- 1 alen alen 42 Aug 22 10:15 original.txt
Ceo zapis pokazuje komanda stat:
$ stat original.txt File: original.txt Size: 42 Blocks: 8 IO Block: 4096 regular file Device: 8,2 Inode: 1310721 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1000/ alen) Gid: ( 1000/ alen) Access: 2026-08-22 10:15:03 +0200 Modify: 2026-08-22 10:15:03 +0200 Change: 2026-08-22 10:15:03 +0200
Pogledaj spisak još jednom: imena nema nigde. Ime živi u direktorijumu.
Direktorijum je tabela
Direktorijum nije kutija u kojoj su fajlovi. To je fajl koji sadrži spisak parova ime → broj inode-a:
ime inode ---------------------- . 1310720 .. 1179649 original.txt 1310721 slika.png 1310730
Odatle sledi sve ostalo. Kad kucaš cat original.txt, sistem
u direktorijumu potraži to ime, dobije broj 1310721, pročita inode i sa
njega sazna gde su blokovi sa sadržajem.
Odatle sledi i nešto što početnike redovno iznenadi: za brisanje ili preimenovanje fajla nisu ti potrebne dozvole nad samim fajlom, nego nad direktorijumom u kome se nalazi. Menjaš tabelu, ne fajl. Zato možeš da obrišeš fajl koji ne smeš ni da otvoriš — o čemu ima više na stranici Pregled prava pristupa.
Hard link: drugo ime za isti inode
Komanda ln bez opcija dodaje novo ime u tabelu, koje pokazuje na već postojeći inode:
$ ln original.txt kopija.txt $ ls -li 1310721 -rw-r--r-- 2 alen alen 42 Aug 22 10:15 kopija.txt 1310721 -rw-r--r-- 2 alen alen 42 Aug 22 10:15 original.txt
Dve stvari u ovom ispisu su bitne. Broj inode-a je isti — to nisu dva fajla, nego jedan fajl sa dva imena. A broj u drugoj koloni skočio je sa 1 na 2; to je broj linkova, odnosno koliko imena pokazuje na taj inode.
Pošto je fajl jedan, promena je odmah vidljiva „na oba mesta":
$ echo "nova linija" >> kopija.txt $ cat original.txt prvi red nova linija
Isto važi i za dozvole i vlasništvo, jer i oni sede na inode-u:
$ chmod 600 kopija.txt $ ls -li 1310721 -rw------- 2 alen alen 54 Aug 22 10:22 kopija.txt 1310721 -rw------- 2 alen alen 54 Aug 22 10:22 original.txt
Nema „originala" i „kopije". Imena su potpuno ravnopravna — sistem ne pamti koje je nastalo prvo.
Dva ograničenja
Hard link ne može preko granice fajl sistema, jer su brojevi inode-a jedinstveni samo unutar jednog fajl sistema:
$ ln original.txt /mnt/backup/original.txt ln: failed to create hard link '/mnt/backup/original.txt': Invalid cross-device link
I ne može na direktorijum:
$ ln dokumenti dok2 ln: dokumenti: hard link not allowed for directory
Kad bi bilo dozvoljeno, stablo direktorijuma prestalo bi da bude stablo i lako bi se dobio ciklus iz koga find ne bi znao da izađe.
Usput: zašto direktorijumi imaju bar 2 linka
$ ls -ld dokumenti drwxr-xr-x 4 alen alen 4096 Aug 22 10:30 dokumenti
Broj 4 nije broj fajlova unutra. Direktorijum ima jedan link od svog imena
u roditelju, jedan od sopstvenog ., i po jedan od
.. u svakom poddirektorijumu. Znači: 2 + broj poddirektorijuma.
Ovde su to dva poddirektorijuma.
Zašto brisanje ne briše
Sad dolazi ono zbog čega cela priča ima praktičnu vrednost.
rm ne briše fajl. On uklanja ime iz
direktorijuma i umanji broj linkova za jedan. Sistemski poziv iza toga i
zove se unlink.
$ rm original.txt $ ls -li 1310721 -rw------- 1 alen alen 54 Aug 22 10:22 kopija.txt $ cat kopija.txt prvi red nova linija
Sadržaj je netaknut, jer je ostalo još jedno ime. Blokovi na disku oslobađaju se tek kada su ispunjena oba uslova:
- broj linkova je pao na nulu, i
- nijedan proces nema taj fajl otvoren
Drugi uslov je onaj koji ume da pojede popodne.
Disk je pun, a obrisao sam sve
Tipičan scenario — servis je popunio disk ogromnim logom:
$ df -h /var Filesystem Size Used Avail Use% Mounted on /dev/sda3 20G 20G 0 100% /var $ sudo rm /var/log/aplikacija.log $ df -h /var Filesystem Size Used Avail Use% Mounted on /dev/sda3 20G 20G 0 100% /var
Ni bajta nazad. Razlog je što servis i dalje drži fajl otvoren, pa
sistem ne sme da oslobodi blokove. Takve fajlove izlistava
lsof +L1 — „otvoreni, a imaju manje od jednog imena":
$ sudo lsof +L1 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME aplikacij 1842 root 7w REG 8,3 8589934592 0 1441795 /var/log/aplikacija.log (deleted)
Oznaka (deleted) i NLINK 0 su potpis ovog
problema. Rešenja su dva:
$ sudo systemctl restart aplikacija
ili, ako restart nije opcija, isprazni fajl kroz deskriptor koji proces
i dalje drži otvorenim (PID i broj FD su iz lsof ispisa):
$ sudo truncate -s 0 /proc/1842/fd/7 $ df -h /var Filesystem Size Used Avail Use% Mounted on /dev/sda3 20G 12G 7,2G 63% /var
Pouka: log fajl se ne prazni komandom rm, nego sa
truncate -s 0 fajl ili > fajl. Tako inode ostaje
isti, proces nastavlja da piše u njega, a prostor se stvarno oslobodi.
Ista logika u drugom smeru
Obrnuto: ako neki program radi nad fajlom koji si u međuvremenu obrisao,
on to neće ni primetiti. Zato tail -f ume da „zamrzne" —
prati inode, a ne ime, pa kad logrotate zameni fajl novim, tvoj
tail i dalje gleda stari, obrisani inode. Rešenje je
tail -F, koji prati ime. Više o tome na stranici
tail.
Simbolički link: putokaz, a ne ime
Simbolički link (skraćeno symlink) je sasvim drugačija stvar. To je poseban, mali fajl sa sopstvenim inode-om, čiji je sadržaj — tekst putanje ka nečemu drugom.
$ ln -s /var/www/sajt/index.html pocetna $ ls -li 1310721 -rw------- 1 alen alen 54 Aug 22 10:22 kopija.txt 1310755 lrwxrwxrwx 1 alen alen 27 Aug 22 10:40 pocetna -> /var/www/sajt/index.html
Tip je l, inode je drugačiji, a veličina je 27 — tačno broj
znakova u putanji koju link sadrži. Dozvole lrwxrwxrwx su uvek
takve i ništa ne znače; važe dozvole fajla na koji se pokazuje.
Kuda link vodi, pokazuje readlink:
$ readlink pocetna /var/www/sajt/index.html $ readlink -f pocetna /var/www/sajt/index.html
Za razliku od hard linka, symlink sme preko fajl sistema, sme na direktorijum, i sme da pokazuje na nešto što uopšte ne postoji:
$ ln -s /nema/ovoga.txt slomljen $ ls -l slomljen lrwxrwxrwx 1 alen alen 15 Aug 22 10:45 slomljen -> /nema/ovoga.txt $ cat slomljen cat: slomljen: No such file or directory
Sve slomljene linkove u stablu pronalaziš ovako:
$ find . -xtype l ./slomljen
Zamka: relativna putanja u symlinku
Ovo je najčešća greška sa simboličkim linkovima:
$ cd /home/alen $ ln -s skripte/backup.sh /usr/local/bin/backup $ backup bash: /usr/local/bin/backup: No such file or directory
Link čuva tekst skripte/backup.sh doslovno, a taj tekst se
razrešava u odnosu na direktorijum u kome link stoji — dakle
/usr/local/bin/skripte/backup.sh, čega nema. Nije bitno odakle
si kucao ln.
Zato: symlink na sistemsko mesto uvek pravi sa apsolutnom putanjom.
$ sudo ln -sf /home/alen/skripte/backup.sh /usr/local/bin/backup
Relativne putanje su korisne unutar jednog stabla koje se seli u komadu — tada linkovi ostaju ispravni i na novoj lokaciji. Podsetnik na to kako se putanje računaju ima u lekciji Apsolutne i relativne putanje.
Zamka: kosa crta na kraju
Ako trenutni pokazuje na direktorijum:
$ rm trenutni # brise link, direktorijum ostaje $ rm trenutni/ # rm: cannot remove 'trenutni/': Not a directory
Kosa crta na kraju znači „kroz link, u sam direktorijum". Zato
ls trenutni prikazuje link, a ls trenutni/ njegov
sadržaj. Ista razlika ume da napravi štetu sa
rsync i cp -r.
Hard vs. simbolički — kad koji
- Hard link — isti inode, ravnopravna imena, ne može preko fajl sistema ni na direktorijum, preživljava brisanje „originala“.
- Symlink — sopstveni inode, sadrži putanju, može bilo gde, pukne ako meta nestane ili se premesti.
U praksi: symlink u devet od deset slučajeva, jer je vidljiv i jasan —
odmah vidiš u ls -l šta na šta pokazuje. Hard linkovi su korak
za sebe i najčešće ih srećeš u alatima za backup (rsync sa
--link-dest), gde se nepromenjeni fajlovi hard-linkuju umesto da
se kopiraju, pa deset snimaka zauzima prostor jednog.
Kad ponestane inode-ova
Broj inode-a se kod ext4 fiksira pri formatiranju. Moguće je da ih potrošiš, a da na disku ima mesta:
$ touch novi.txt touch: cannot touch 'novi.txt': No space left on device $ df -h / Filesystem Size Used Avail Use% Mounted on /dev/sda2 50G 18G 30G 38% / $ df -i / Filesystem Inodes IUsed IFree IUse% Mounted on /dev/sda2 3276800 3276800 0 100% /
Poruka govori o prostoru, ali df -h kaže da ga ima. Kad ovo
vidiš, odmah proveri df -i. Krivac su obično milioni sitnih
fajlova — sesije, keš, neisporučena pošta. Gde ih ima najviše:
$ sudo find /var -xdev -type f | cut -d/ -f1-4 | sort | uniq -c | sort -rn | head 892431 /var/lib/php/sessions 41102 /var/spool/postfix/maildrop
Ovo je i lep primer spajanja komandi iz lekcije Piping i redirekcija. Napomena: du ti ovde ne pomaže, jer meri zauzeće u bajtovima, a problem je u broju fajlova.
Praktični trikovi sa brojem inode-a
Brisanje fajla čije ime je problem
$ ls -li 1310745 -rw-r--r-- 1 alen alen 0 Aug 22 11:02 -rf $ find . -maxdepth 1 -inum 1310745 -delete
Radi za imena sa crticom, razmacima, navodnicima ili nevidljivim znakovima, gde bi normalno trebalo pažljivo štititi ime navodnicima (Džokeri i navodnici).
Pronalaženje svih imena jednog fajla
$ find /home -samefile kopija.txt /home/alen/kopija.txt /home/alen/arhiva/stara-kopija.txt
Provera da li su dva fajla zapravo isti fajl
$ ls -i a.txt b.txt 1310721 a.txt 1310721 b.txt
Isti broj — isti fajl. Ovo je pouzdanije od poređenja sadržaja komandom diff, koje samo kaže da su identični.
Jedna napomena o editorima
Mnogi editori, uključujući vim u podrazumevanoj postavci, ne pišu u postojeći fajl nego naprave novi i preimenuju ga preko starog. Rezultat:
$ ls -li kopija.txt 1310721 -rw-r--r-- 2 alen alen 54 Aug 22 10:22 kopija.txt $ vim kopija.txt # izmena i :wq $ ls -li kopija.txt 1310902 -rw-r--r-- 1 alen alen 61 Aug 22 11:15 kopija.txt
Inode je drugačiji, broj linkova pao na 1 — hard link je pukao i drugo ime i dalje pokazuje na stari sadržaj. Symlink u istoj situaciji preživljava, jer prati ime. Još jedan razlog zašto su symlinkovi u svakodnevnom radu manje opasan izbor.
Kratka referenca
ls -li— broj inode-a i broj linkovastat fajl— ceo inode zapisln meta ime— hard linkln -s meta ime— simbolički linkln -sf meta ime— zameni postojeći linkreadlink -f link— kuda link zaista vodifind . -xtype l— slomljeni linkovifind . -samefile fajl— sva imena istog inode-adf -i— potrošnja inode-ovalsof +L1— obrisani fajlovi koje procesi drže otvorenetruncate -s 0 fajl— pravilan način da se isprazni log
Vežba
$ mkdir ~/vezba-inode && cd ~/vezba-inode $ echo "prvi red" > podaci.txt $ ln podaci.txt hard.txt $ ln -s podaci.txt soft.txt $ ls -li
Pre nego što izvršiš, pokušaj da predvidiš odgovore:
- Koliki je broj linkova na
podaci.txti zaštosoft.txtnije uticao na njega? - Šta se dešava sa
hard.txt, a šta sasoft.txtposlerm podaci.txt? - Posle brisanja, napravi ponovo
echo "drugi red" > podaci.txt. Da lisoft.txtproradi? Da lihard.txtvidi novi sadržaj? Proveri brojeve inode-a i objasni sebi zašto.
Treći zadatak je cela lekcija u tri komande.
Osnovne komande za linkove i njihove opcije su na stranici ln.
Cela lekcija je deo vodiča Linux osnove.
Comments
Post a Comment