Allt du någonsin velat veta om inoder på Linux

Linux-filsystemet är beroende av inoder. Dessa viktiga delar av filsystemets inre funktion missförstås ofta. Låt oss titta på exakt vad de är och vad de gör.

Elementen i ett filsystem

Per definition behöver ett filsystem lagra filer, och de innehåller även kataloger. Filerna lagras i katalogerna, och dessa kataloger kan ha underkataloger. Något, någonstans, måste registrera var alla filer finns i filsystemet, vad de heter, vilka konton de tillhör, vilka behörigheter de har och mycket mer. Denna information kallas metadata eftersom det är data som beskriver annan data.

I Linux ext4 filsystemet, den inode och katalogstrukturer arbeta tillsammans för att tillhandahålla ett underbyggande ramverk som lagrar all metadata för varje fil och katalog. De gör metadata tillgänglig för alla som behöver det, oavsett om det är kärnan, användarapplikationer eller Linux-verktyg, som ls, stat och df.

Inoder och filsystemstorlek

Även om det är sant att det finns ett par strukturer, kräver ett filsystem mycket mer än så. Det finns tusentals och åter tusentals av varje struktur. Varje fil och katalog kräver en inod, och eftersom varje fil finns i en katalog, kräver varje fil också en katalogstruktur. Katalogstrukturer kallas också katalogposter eller ”dentries”.

Varje inod har ett inodnummer, som är unikt inom ett filsystem. Samma inodnummer kan förekomma i mer än ett filsystem. Filsystems-ID och inodnummer kombineras dock för att skapa en unik identifierare, oavsett hur många filsystem som är monterade på ditt Linux-system.

Kom ihåg att i Linux monterar du inte en hårddisk eller partition. Du monterar filsystemet som finns på partitionen, så det är lätt att ha flera filsystem utan att inse det. Om du har flera hårddiskar eller partitioner på en enda enhet, har du mer än ett filsystem. De kan vara av samma typ – alla ext4 till exempel – men de kommer fortfarande att vara distinkta filsystem.

Alla inoder hålls i ett bord. Med hjälp av ett inodnummer beräknar filsystemet enkelt offset i inodtabellen där den inoden finns. Du kan se varför ”i” i inod står för index.

Variabeln som innehåller inodnumret deklareras i källkoden som ett 32-bitars långt heltal utan tecken. Detta betyder att inodnumret är ett heltalsvärde med en maximal storlek på 2^32, vilket beräknas till 4 294 967 295 – långt över 4 miljarder inoder.

Det är det teoretiska maxvärdet. I praktiken bestäms antalet inoder i ett ext4-filsystem när filsystemet skapas med ett standardförhållande på en inod per 16 KB filsystemkapacitet. Katalogstrukturer skapas i farten när filsystemet används, eftersom filer och kataloger skapas i filsystemet.

Det finns ett kommando som du kan använda för att se hur många inoder som finns i ett filsystem på din dator. Alternativet -i (inoder) för kommandot df instruerar det att visa dess utdata i antal inoder.

Vi ska titta på filsystemet på den första partitionen på den första hårddisken, så vi skriver följande:

df -i /dev/sda1

De

Utgången ger oss:

Filsystem: Filsystemet som rapporteras om.
Inoder: Det totala antalet inoder i detta filsystem.
IUsed: Antalet inoder som används.
IFree: Antalet återstående inoder som är tillgängliga för användning.
IUse%: Procentandelen använda inoder.
Monterad på: Monteringspunkten för detta filsystem.

Vi har använt 10 procent av inoderna i det här filsystemet. Filer lagras på hårddisken i diskblock. Varje inod pekar på skivblocken som lagrar innehållet i filen de representerar. Om du har miljontals små filer kan du få slut på inoder innan du får slut på hårddiskutrymme. Det är dock ett mycket svårt problem att stöta på.

Tidigare hade vissa e-postservrar som lagrade e-postmeddelanden som diskreta filer (vilket snabbt ledde till stora samlingar av små filer) detta problem. När dessa applikationer ändrade sina baksidor till databaser löste detta dock problemet. Det genomsnittliga hemsystemet kommer inte att ta slut på inoder, vilket är lika bra eftersom du med ext4-filsystemet inte kan lägga till fler inoder utan att installera om filsystemet.

Att se storleken på diskblocken i ditt filsystemkan du använda blockdev-kommandot med alternativet –getbsz (get block size):

sudo blockdev --getbsz /dev/sda

De

Blockstorleken är 4096 byte.

Låt oss använda alternativet -B (blockstorlek) för att ange en blockstorlek på 4096 byte och kontrollera den vanliga diskanvändningen:

df -B 4096 /dev/sda1

De

Denna utdata visar oss:

Filsystem: Filsystemet som vi rapporterar om.
4K-block: Det totala antalet 4 KB-block i detta filsystem.
Används: Hur många 4K-block används.
Tillgänglig: Antalet återstående 4 KB-block som är tillgängliga för användning.
Använd%: Procentandelen av 4 KB-block som har använts.
Monterad på: Monteringspunkten för detta filsystem.

I vårt exempel har fillagring (och lagring av inoderna och katalogstrukturerna) använt 28 procent av utrymmet på det här filsystemet, till priset av 10 procent av inoderna, så vi är i bra form.

Inode Metadata

För att se inodnumret för en fil kan vi använda ls med alternativet -i (inod):

ls -i geek.txt

Inodnumret för denna fil är 1441801, så denna inod innehåller metadata för denna fil och, traditionellt, pekarna till diskblocken där filen finns på hårddisken. Om filen är fragmenterad, mycket stor eller båda, kan några av blocken som inoden pekar på hålla ytterligare pekare till andra diskblock. Och några av dessa andra diskblock kan också hålla pekare till en annan uppsättning diskblock. Detta övervinner problemet med att inoden har en fast storlek och kan hålla ett ändligt antal pekare till skivblock.

Den metoden ersattes av ett nytt schema som använder ”omfång.” Dessa registrerar start- och slutblocket för varje uppsättning av sammanhängande block som används för att lagra filen. Om filen är ofragmenterad behöver du bara lagra det första blocket och fillängden. Om filen är fragmenterad måste du lagra det första och sista blocket i varje del av filen. Denna metod är (uppenbarligen) mer effektiv.

Om du vill se om ditt filsystem använder diskblockpekare eller omfattningar kan du titta inuti en inod. För att göra det använder vi kommandot debugfs med alternativet -R (request), och skicka den inoden till filen av intresse. Detta ber debugfs att använda sitt interna ”stat”-kommando för att visa innehållet i inoden. Eftersom inodnummer bara är unika inom ett filsystem, måste vi också berätta för debugfs vilket filsystem som inoden finns på.

Så här skulle det här exempelkommandot se ut:

sudo debugfs -R "stat " /dev/sda1

De ” /dev/sda1″ kommando i ett terminalfönster.’ width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);” onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”>

Som visas nedan extraherar kommandot debugfs informationen från inoden och presenterar den för oss på mindre:

Vi visas följande information:

Inode: Numret på inoden vi tittar på.
Typ: Detta är en vanlig fil, inte en katalog eller symbolisk länk.
Läge: Filbehörigheterna i oktal.
Flaggor: Indikatorer som representerar olika egenskaper eller funktionalitet. 0x80000 är ”extents”-flaggan (mer om detta nedan).
Generation: A Nätverksfilsystem (NFS) använder detta när någon får åtkomst till fjärrfilsystem över en nätverksanslutning som om de var monterade på den lokala maskinen. Inod- och generationsnumren används som en form av filhandtag.
Version: Inodeversionen.
Användare: Ägaren till filen.
Grupp: Gruppägaren till filen.
Projekt: Bör alltid vara noll.
Storlek: Storleken på filen.
Fil ACL: Listan för filåtkomstkontroll. Dessa har utformats för att du ska kunna ge kontrollerad åtkomst till personer som inte är med i ägargruppen.
Länkar: Antalet hårda länkar till filen.
Blockantal: Mängden hårddiskutrymme som allokerats till denna fil, angivet i 512-byte bitar. Vår fil har tilldelats åtta av dessa, vilket är 4 096 byte. Så vår 98-byte fil sitter inom ett enda 4 096-byte diskblock.
Fragment: Den här filen är inte fragmenterad. (Detta är en föråldrad flagga.)
Ctime: Tiden då filen skapades.
Atime: Tidpunkten då denna fil senast öppnades.
Mtime: Tiden då denna fil senast ändrades.
Crtime: Tiden då filen skapades.
Storlek på extra inodfält: Filsystemet ext4 introducerade möjligheten att allokera en större inod på disken vid formateringstidpunkten. Detta värde är antalet extra byte som inoden använder. Detta extra utrymme kan också användas för att tillgodose framtida krav på nya kärnor eller för att lagra utökade attribut.
Inodkontrollsumma: En kontrollsumma för denna inod, som gör det möjligt att upptäcka om inoden är skadad.
Omfattningar: Om omfattningar används (på ext4 är de, som standard), har metadata om diskblocksanvändning av filer två siffror som indikerar start- och slutblocken för varje del av en fragmenterad fil. Detta är mer effektivt än att lagra varje diskblock som tas upp av varje del av en fil. Vi har en omfattning eftersom vår lilla fil sitter i ett diskblock vid denna blockoffset.

Var är filnamnet?

Vi har nu mycket information om filen, men som du kanske har märkt fick vi inte filnamnet. Det är här katalogstrukturen kommer in i bilden. I Linux, precis som en fil, har en katalog en inod. Istället för att peka på diskblock som innehåller fildata, pekar dock en kataloginod på diskblock som innehåller katalogstrukturer.

Jämfört med en inode innehåller en katalogstruktur en begränsad mängd information om en fil. Den innehåller bara filens inodnummer, namn och längden på namnet.

Inoden och katalogstrukturen innehåller allt du (eller ett program) behöver veta om en fil eller katalog. Katalogstrukturen är i ett katalogdiskblock, så vi vet vilken katalog filen finns i. Katalogstrukturen ger oss filnamn och inodnummer. Inoden berättar allt annat om filen, inklusive tidsstämplar, behörigheter och var man kan hitta fildata i filsystemet.

Directory Inoder

Du kan se inodnumret för en katalog lika enkelt som du kan se dem för filer.

I följande exempel kommer vi att använda ls med alternativen -l (långt format), -i (inod) och -d (katalog), och titta på arbetskatalogen:

ls -lid work/

De

Eftersom vi använde alternativet -d (katalog), rapporterar ls om själva katalogen, inte dess innehåll. Inoden för denna katalog är 1443016.

För att upprepa det för hemkatalogen skriver vi följande:

ls -lid ~

De

Inoden för hemkatalogen är 1447510, och arbetskatalogen finns i hemkatalogen. Låt oss nu titta på innehållet i arbetskatalogen. Istället för alternativet -d (katalog), använder vi alternativet -a (alla). Detta kommer att visa oss de katalogposter som vanligtvis är dolda.

Vi skriver följande:

ls -lia work/

De

Eftersom vi använde alternativet -a (alla), visas enkel- (.) och dubbelpunkts (..) poster. Dessa poster representerar själva katalogen (enkel punkt) och dess överordnade katalog (dubbelpunkt.)

Om du tittar på inodnumret för posten med en punkt, ser du att det är 1443016 — samma inodnummer som vi fick när vi upptäckte inodnumret för arbetskatalogen. Dessutom är inodnumret för dubbelpunktsposten detsamma som inodnumret för hemkatalogen.

Det är därför du kan använda kommandot cd .. för att flytta upp en nivå i katalogträdet. På samma sätt, när du föregår ett program eller ett skriptnamn med ./, låter du skalet veta varifrån programmet eller skriptet ska startas.

Inoder och länkar

Som vi har tagit upp krävs tre komponenter för att ha en välformad och tillgänglig fil i filsystemet: filen, katalogstrukturen och inoden. Filen är data som lagras på hårddisken, katalogstrukturen innehåller namnet på filen och dess inodnummer, och inoden innehåller all metadata för filen.

Symboliska länkar är filsystemposter som ser ut som filer, men de är verkligen genvägar som pekar till en befintlig fil eller katalog. Låt oss se hur de klarar detta och hur de tre elementen används för att uppnå detta.

Låt oss säga att vi har en katalog med två filer i den: en är ett skript och den andra är ett program, som visas nedan.

Vi kan använda kommandot ln och alternativet -s (symboliskt) för att skapa en mjuk länk till skriptfilen, så här:

ls -s my_script geek.sh

De

Vi har skapat en länk till my_script.sh som heter geek.sh. Vi kan skriva följande och använda ls för att titta på de två skriptfilerna:

ls -li *.sh

De

Posten för geek.sh visas i blått. Det första tecknet i behörighetsflaggorna är ett ”l” för länk, och -> pekar på my_script.sh . Allt detta indikerar att geek.sh är en länk.

Som du förmodligen förväntar dig har de två skriptfilerna olika inodnummer. Vad som dock kan vara mer överraskande är att den mjuka länken, geek.sh, inte har samma användarbehörighet som den ursprungliga skriptfilen. Faktum är att behörigheterna för geek.sh är mycket mer liberala – alla användare har fullständiga behörigheter.

Katalogstrukturen för geek.sh innehåller namnet på länken och dess inod. När du försöker använda länken refereras dess inod, precis som en vanlig fil. Länkinoden kommer att peka på ett diskblock, men istället för att innehålla filinnehållsdata innehåller diskblocket namnet på originalfilen. Filsystemet omdirigerar till originalfilen.

Vi tar bort originalfilen och ser vad som händer när vi skriver följande för att se innehållet i geek.sh:

rm my_script.sh
cat geek.sh

De

Den symboliska länken är bruten och omdirigeringen misslyckas.

Vi skriver nu följande för att skapa en hård länk till applikationsfilen:

ln special-app geek-app

De

För att titta på inoderna för dessa två filer skriver vi följande:

ls -li

De

Båda ser ut som vanliga filer. Inget om geek-app indikerar att det är en länk på det sätt som ls-listan för geek.sh gjorde. Dessutom har geek-app samma användarbehörigheter som originalfilen. Men vad som kan vara förvånande är att båda applikationerna har samma inodnummer: 1441797.

Katalogposten för geek-app innehåller namnet ”geek-app” och ett inodnummer, men det är samma som inodnumret för originalfilen. Så vi har två filsystemposter med olika namn som båda pekar på samma inod. Faktum är att hur många objekt som helst kan peka på samma inod.

Vi skriver följande och använder statprogrammet för att titta på målfilen:

stat special-app

De

Vi ser att två hårda länkar pekar på denna fil. Detta lagras i inoden.

I följande exempel tar vi bort originalfilen och försöker använda länken med en hemligt, säkert lösenord:

rm special-app
./geek-app correcthorsebatterystaple

De

Överraskande nog fungerar applikationen som förväntat, men hur? Det fungerar eftersom, när du tar bort en fil, är inoden fri att återanvändas. Katalogstrukturen är markerad som att ha inodnumret noll, och diskblocken är sedan tillgängliga för en annan fil som kan lagras i det utrymmet.

Om antalet hårda länkar till inoden är större än en reduceras dock antalet hårda länkar med en och inodnumret för katalogstrukturen för den borttagna filen sätts till noll. Filinnehållet på hårddisken och inoden är fortfarande tillgängligt för befintliga hårdlänkar.

Vi kommer att skriva följande och använda stat en gång till – den här gången på geek-app:

stat geek-app

De

Dessa detaljer hämtas från samma inod (1441797) som föregående stat-kommando. Antalet länkar minskades med en.

Eftersom vi har en hård länk till denna inode, om vi tar bort geek-app, skulle den verkligen ta bort filen. Filsystemet frigör inoden och markerar katalogstrukturen med en inod på noll. En ny fil kan sedan skriva över datalagringen på hårddisken.

Inode Overheads

det är ett snyggt system, men det finns omkostnader. För att läsa en fil måste filsystemet göra allt följande:

Hitta rätt katalogstruktur
Läs inodnumret
Hitta rätt inod
Läs inodinformationen
Följ antingen inodlänkarna eller omfattningen till relevanta diskblock
Läs fildata

Lite mer att hoppa runt är nödvändigt om data inte är sammanhängande.

Föreställ dig det arbete som måste göras för att ls ska utföra en långformatsfillista med många filer. Det är mycket fram och tillbaka bara för att få den information den behöver för att generera sin produktion.

Naturligtvis är att snabba upp filsystemåtkomsten varför Linux försöker göra så mycket förebyggande filcache som möjligt. Detta hjälper mycket, men ibland – som med alla filsystem – kan omkostnaderna bli uppenbara.

Nu vet du varför.