Finestre.  Virus.  I Quaderni.  Internet.  ufficio.  Utilità.  Autisti

Come con qualsiasi file system UNIX, ext2 può essere suddiviso nei seguenti componenti:

− blocchi e gruppi di blocchi;

− indice descrittore;

− superblocco.

L'intero spazio della partizione del disco è suddiviso in blocchi di dimensioni fisse che sono multipli della dimensione del settore: 1024, 2048, 4096 o 8192 byte. La dimensione del blocco viene specificata durante la creazione di un file system su una partizione del disco. Una dimensione di blocco più piccola consente di risparmiare spazio su disco rigido, ma limita anche la dimensione massima del file system. Tutti i blocchi hanno numeri di serie. Per ridurre la frammentazione e il numero di movimenti della testina del disco rigido durante la lettura di grandi array di dati, i blocchi vengono combinati in gruppi di blocchi.

Il concetto di base di un file system è un inode, o inode (nodo di informazioni). Questa è una struttura speciale che contiene informazioni sugli attributi e sulla posizione fisica di un file. Gli inode sono organizzati in una tabella contenuta all'inizio di ogni gruppo di blocchi.

Figura 10 - Schema a blocchi generalizzato di FS ext2

Il superblocco è l'elemento principale del file system ext2. Contiene informazioni generali sul file system:

il numero totale di blocchi e inode nel file system,

il numero di blocchi e inode liberi nel file system,

dimensione del blocco del file system,

il numero di blocchi e inode in un gruppo di blocchi,

dimensione dell'inode,

identificatore del file system.

Il superblocco è a 1024 byte dall'inizio della sezione. La salute del file system dipende direttamente dall'integrità del superblocco. Il sistema operativo crea diverse copie di backup del superblocco nel caso in cui la partizione sia danneggiata. Il blocco successivo dopo il superblocco contiene la tabella dei descrittori globali, una descrizione dei gruppi di blocchi, che è un array contenente informazioni generali su tutti i gruppi di blocchi nella sezione.

Tutti i blocchi su una partizione ext2 sono divisi in gruppi di blocchi. Per ogni gruppo, viene creata una voce separata nella tabella dei descrittori globali, che memorizza i parametri principali:

numero di blocco nella bitmap del blocco,

il numero di blocco nella bitmap inode,

numero di blocco nella tabella degli inode,

il numero di blocchi liberi nel gruppo,

il numero di inode contenenti directory.

Una bitmap di blocco è una struttura, ogni bit della quale indica se il blocco corrispondente è assegnato a un file. Se il bit è 1, allora il blocco è occupato. Una funzione simile è svolta dalla bitmap inode, che mostra quali inode sono occupati e quali no. Kernel Linux, utilizzando il numero di inode contenenti directory, cerca di distribuire equamente gli inode di directory tra i gruppi e cerca di spostare gli inode di file nel gruppo con la directory principale, se possibile. Tutto lo spazio rimanente, indicato nella tabella come dati, è riservato alla memorizzazione dei file.

Sistema di file ext2 utilizza il seguente schema di indirizzamento dei blocchi di file. Per memorizzare l'indirizzo del file, vengono assegnati 15 campi, ciascuno dei quali è composto da 4 byte. Se il file rientra in 12 blocchi, i numeri dei cluster corrispondenti vengono elencati direttamente nei primi dodici campi dell'indirizzo. Se la dimensione del file supera i 12 blocchi, il campo successivo contiene l'indirizzo del cluster in cui possono essere posizionati i numeri dei blocchi successivi del file. Pertanto, il 13° campo viene utilizzato per l'indirizzamento indiretto.

Con una dimensione massima del blocco di 4096 byte, il cluster corrispondente al 13° campo può contenere fino a 1024 numeri di blocco successivo nel file. Se la dimensione del file supera 12+1024 blocchi, viene utilizzato il 14° campo, che contiene l'indirizzo di un cluster contenente 1024 numeri di cluster, ciascuno dei quali fa riferimento a 1024 blocchi del file. Qui viene utilizzato il doppio indirizzamento indiretto. Infine, se il file contiene più di 12+1024+1048576 blocchi, l'ultimo 15° campo viene utilizzato per il triplo indirizzamento.

Questo sistema l'indirizzamento consente, con una dimensione massima del blocco di 4096 byte, di avere file superiori a 2 TB.

ext3 o ext3fs è un file system journaling utilizzato nei sistemi operativi basati sul kernel Linux. Basato su FS ext2.

La differenza principale rispetto a ext2 è che ext3 è journaled, ovvero prevede la scrittura di alcuni dati che consentono di ripristinare il file system in caso di crash del computer.

Lo standard prevede tre modalità di registrazione:

writeback: nel journal vengono scritti solo i metadati del file system, ovvero le informazioni sulla sua modifica. Non può garantire l'integrità dei dati, ma riduce già notevolmente i tempi di verifica rispetto a ext2;

ordinato: uguale al writeback, ma i dati vengono scritti nel file prima di scrivere le informazioni sulla modifica di questo file. Riduce leggermente le prestazioni, inoltre non può garantire l'integrità dei dati (sebbene aumenti la probabilità della loro sicurezza quando si aggiunge alla fine di un file esistente);

journal: journaling completo sia dei metadati FS che dei dati utente. Il più lento ma anche il più modalità sicura; può garantire l'integrità dei dati quando si memorizza il registro su una partizione separata (o meglio, su un disco rigido separato).

Il file system ext3 può supportare file di dimensioni fino a 1 TB. Con il kernel Linux 2.4, la dimensione del file system è limitata dalla dimensione massima del dispositivo a blocchi, che è di 2 terabyte. In Linux 2.6 (per processori a 32 bit), la dimensione massima del dispositivo a blocchi è di 16 TB, tuttavia ext3 supporta solo fino a 4 TB.

ext4 è un file system basato e compatibile con ext3 (avanti e indietro). Differisce da ext3 nel supporto delle estensioni, gruppi di blocchi fisici contigui gestiti come un tutt'uno, maggiore velocità di verifica dell'integrità e una serie di altri miglioramenti.

Nuove funzionalità ext4 (rispetto a ext3):

Utilizzo delle estensioni. Nel filesystem ext3, i dati venivano indirizzati in modo tradizionale, blocco per blocco. Questo metodo di indirizzamento diventa meno efficiente con l'aumentare delle dimensioni del file. Gli extent consentono di indirizzare un numero elevato (fino a 128 MB) di blocchi contigui con un unico descrittore. È possibile posizionare direttamente nell'inode fino a 4 puntatori di estensione, sufficienti per file di dimensioni medio-piccole.

Numeri di blocco a 48 bit. Con una dimensione del blocco di 4K, ciò consente di indirizzare fino a un exabyte (2 48 *4KB = 2 50 *1KB = 2 60 B = 1 EB).

Assegnazione di blocchi in gruppi (allocazione multiblocco). Il file system memorizza non solo le informazioni sulla posizione dei blocchi liberi, ma anche il numero di blocchi liberi che si susseguono. Quando si alloca lo spazio, il file system trova un frammento in cui i dati possono essere scritti senza frammentazione. Ciò riduce il livello di frammentazione del file system nel suo complesso.

Assegnazione ritardata dei blocchi. L'allocazione dei blocchi per l'archiviazione dei dati dei file avviene immediatamente prima della scrittura fisica su disco (ad esempio, quando si chiama la sincronizzazione) e non quando si chiama la scrittura. Di conseguenza, le operazioni di allocazione dei blocchi possono essere eseguite non una alla volta, ma in gruppi, il che a sua volta riduce al minimo la frammentazione e accelera il processo di allocazione dei blocchi. D'altra parte, aumenta il rischio di perdita di dati in caso di improvvisa interruzione di corrente.

Il limite di 32000 directory è stato superato.

Prenotazione di inode durante la creazione di una directory (prenotazione directory inode) Durante la creazione di una directory, vengono riservati diversi inode. Successivamente, durante la creazione di file in questa directory, vengono utilizzati per primi gli inode riservati e, se non ne sono rimasti, viene seguita la procedura consueta.

dimensione dell'inode. La dimensione dell'inode (impostazione predefinita) è aumentata da 128 byte a 256 byte. Ciò ha permesso di realizzare i vantaggi elencati di seguito.

Timestamp con precisione al nanosecondo (nanosecond timestamp). Maggiore precisione dei tempi memorizzati in inode. Anche l'intervallo degli orari memorizzati è stato ampliato: se prima il limite massimo dell'orario memorizzato era il 18 gennaio 2038, ora è il 25 aprile 2514.

versione inode. L'inode ha un numero che aumenta ogni volta che l'inode del file viene modificato.

Archiviazione di attributi estesi in un inode (EA in inode). La memorizzazione di attributi estesi come ACL, attributi SELinux e così via può migliorare le prestazioni. Gli attributi per i quali non c'è spazio inode sufficiente vengono archiviati in un blocco separato da 4 KB.

Checksum del diario. Checksum delle transazioni di log. Consente di trovare meglio e (a volte) correggere gli errori durante il controllo dell'integrità del sistema dopo un arresto anomalo.

Assegnazione preliminare (preassegnazione persistente). Ora, per garantire che l'applicazione occupi spazio nel file system, lo riempie di zeri. In ext4 è diventato possibile riservare molti blocchi per la scrittura e non dedicare troppo tempo all'inizializzazione. Se l'applicazione tenta di leggere i dati, riceverà un messaggio che non è stato inizializzato. Pertanto, la lettura non autorizzata dei dati cancellati non funzionerà.

Deframmentazione senza smontaggio (deframmentazione online).

Blocchi non inizializzati. Consente di velocizzare il controllo del file system. I blocchi contrassegnati come inutilizzati vengono controllati in gruppi e viene eseguito un controllo dettagliato solo se il controllo del gruppo ha mostrato che vi sono danni all'interno.

Lezione 12

Oggetto: sistemi di directory

Il collegamento tra il sistema di gestione dei file e l'insieme dei file è cartella dei file. La forma più semplice di un sistema di directory è che esiste una directory che contiene tutti i file. La directory contiene informazioni sui file, inclusi attributi, posizione, proprietà. Gli utenti fanno riferimento ai file con nomi simbolici. Tuttavia, la capacità della memoria umana limita il numero di nomi di oggetti a cui un utente può fare riferimento per nome. L'organizzazione gerarchica dello spazio dei nomi consente di espandere notevolmente questi confini. Ecco perché i sistemi di directory hanno struttura gerarchica. Un grafico che descrive una gerarchia di directory può essere un albero o una rete. Le directory formano un albero se un file può trovarsi in una sola directory (Figura 7.11) e una rete se un file può trovarsi in più di una directory.

Ad esempio, in Ms-Dos e Directory di Windows formano una struttura ad albero e in UNIX una struttura di rete. Generalmente sistema informatico può avere diversi dispositivi disco, anche un PC ha sempre diversi dischi: flessibile, disco rigido, CD-ROM (DVD). Come organizzare l'archiviazione dei file in questo caso?

Riso. Sistemi di directory

La prima soluzione è ospitare un file system offline su ciascun dispositivo, ad es. i file su questo dispositivo sono descritti da un albero di directory che non ha nulla a che fare con gli alberi di directory su altri dispositivi. In questo caso, per identificare in modo univoco il file, l'utente deve specificare l'identificatore del dispositivo logico insieme al nome del file simbolico composto. Un esempio di tale esistenza autonoma è MS-DOS, Windows 95/98/Me/XP.

Un'altra soluzione è organizzare l'archiviazione dei file in modo tale che all'utente sia data l'opportunità di combinare i file system che si trovano su diversi dispositivi, in un singolo file system descritto da un singolo albero di directory. Questa operazione si chiama montaggio.

Su UNIX, il montaggio viene eseguito come segue. Tra tutti i dispositivi a disco logico disponibili, uno spicca, chiamato il sistema. Lascia che ci siano due file system situati su diversi dischi logici e uno dei dischi è uno di sistema (Fig. 7.12).

Il file system che si trova su unità di sistema, si chiama radice. Per collegare le gerarchie di file nel file system root, viene selezionata una directory esistente, in questo esempio la directory loc. Una volta completato il montaggio, la directory loc selezionata diventa la directory root del secondo file system. Attraverso questa directory, il file system montato è connesso come un sottoalbero all'albero generale.

Riso. Montaggio

Attributo

Il concetto di file include non solo i dati che memorizza e il suo nome, ma anche informazioni che descrivono le proprietà del file. Queste informazioni costituiscono gli attributi del file. L'elenco degli attributi può essere diverso nei diversi sistemi operativi. Di seguito è riportato un esempio di possibili attributi.

Attributo Senso
Tipo di file Normale, catalogo, speciale, ecc.
Proprietario del file Attuale proprietario
Creatore di file ID dell'utente che ha creato il file
Parola d'ordine Password per accedere al file
Tempo Creazione, ultimo accesso, ultima modifica
Dimensione file corrente Numero di byte per voce
Taglia massima Il numero di byte a cui è possibile aumentare la dimensione del file
Flag di sola lettura 0 - lettura / scrittura, 1 - sola lettura
Bandiera "nascosta" 0 - normale, 1 - non mostrato nell'elenco dei file di catalogo
Contrassegna "sistema" 0 - normale, 1 - sistema
Contrassegno "archiviato" 0 - archiviato, 1 - archivio richiesto
Flag/binario ASCII 0 - ASCII, 1 - binario
Contrassegno di accesso casuale 0 - solo accesso sequenziale, 1 - accesso casuale
Segnala "temporaneo" 0 - normale, 1 - cancellazione dopo la fine del processo
Posizione chiave Offset rispetto alla chiave nel record
Lunghezza chiave Numero di byte nel campo chiave

L'utente può accedere agli attributi utilizzando le funzionalità fornite a tale scopo dal file system. Di solito è consentito leggere il valore di qualsiasi attributo e modificarne solo alcuni.

I valori degli attributi dei file possono essere contenuti nelle directory, come avviene, ad esempio, in MS-DOS (Figura 7.7). Un'altra opzione è inserire gli attributi in tabelle speciali, nel qual caso le directory contengono collegamenti a queste tabelle.

Riso. 7. Attributi file MS-DOS

ext2(indicato anche come ext2fs) - Secondo esteso Sistema di file (Second Extended File System) è un file system costruito sul kernel Linux. Il creatore e sviluppatore di ext2 è Remy Card. Il file system ext2 è stato creato da lui per sostituire quello vecchio, versione precedente- int.

In termini di indicatori come velocità e prestazioni, questo file system può fungere da punto di riferimento. Ciò è evidenziato dai risultati dei test delle prestazioni del file system. Ad esempio, nei test sequenziali di velocità di lettura/scrittura del Dell Tech Center, ext2 supera ext3 e supera solo il più moderno ext4 in termini di velocità di lettura.

Il principale svantaggio di ext2 è che non è un file system journaling. Tuttavia, questa lacuna è stata eliminata nel file system successivo: ext3.

ext2 viene utilizzato su schede flash e unità a stato solido(SSD) poiché la mancanza di journaling è un vantaggio quando si lavora con unità con limiti di ciclo di scrittura.

Storia di ext2

Al momento del rapido sviluppo del sistema Linux, utilizzava il file system del sistema operativo Minix. Era abbastanza stabile, ma era a 16 bit. Di conseguenza, aveva un limite rigido di 64 Mb per partizione. Inoltre, c'era un limite alla lunghezza massima di un nome di file, che era di 14 caratteri.

Queste limitazioni combinate furono la ragione per lo sviluppo del "file system esteso" (da qui il termine " File system esteso»). Le è stato affidato il compito di risolvere due dei problemi chiave di Minix. Il nuovo file system è stato reso pubblico nell'aprile 1992. Era Ext, che estendeva il limite della dimensione del file a 2 gigabyte e impostava il limite del nome del file a 255 caratteri.

Tuttavia, nonostante il successo del nuovo file system, c'erano ancora parecchi problemi irrisolti. Ad esempio, non c'era supporto per l'accesso separato, non c'erano timestamp per la modifica dei dati. La necessità di risolvere questi problemi è stato il motivo per creare la prossima versione del file system ext2 esteso (“ Secondo file system esteso). ext2 è stato sviluppato nel gennaio 1993 e implementava anche ACL conformi a POSIX e attributi di file estesi.

Organizzazione logica di ext2

Il grafico della gerarchia di directory ext2 è rappresentato come una rete. Ciò è dovuto al fatto che un file può essere incluso in più directory contemporaneamente.

Tutti i tipi di file hanno nomi simbolici. Nei file system organizzati gerarchicamente vengono generalmente utilizzati tre tipi di nomi: semplice, composto e relativo. Lo stesso con ext2. Nel caso di un nome semplice, la limitazione è che la sua lunghezza non deve superare i 255 caratteri, inoltre, il nome non deve contenere un carattere NULL e una barra.

Come per il carattere NULL le limitazioni sono legate alla rappresentazione delle stringhe nel linguaggio C, nel caso del carattere slash tutto sta nel fatto che viene utilizzato come carattere separatore tra directory.

Il nome completo è una catena di semplici nomi simbolici di tutte le directory attraverso le quali passa il percorso dalla radice a dato file. In ext2, un file può trovarsi in più directory, il che significa che può avere più nomi completi (un file, più nomi completi). Ma comunque, il nome completo definisce il file.

attributi ext2:

  • tipo di file e autorizzazioni,
  • proprietario, gruppo di accesso,
  • informazioni sulle transazioni autorizzate,
  • ora di creazione, data dell'ultimo accesso, data dell'ultima modifica e ora dell'ultima cancellazione,
  • dimensione del file corrente,
  • specifica file:
    • fascicolo regolare,
    • Catalogare,
    • file di dispositivo orientato ai byte,
    • file del dispositivo a blocchi,
    • pipa denominata,
    • collegamento simbolico,
  • numero di blocchi occupati,
  • altri

Gli attributi dei file sono memorizzati in tabelle speciali, non in directory, come è comune nei file system semplici. Di conseguenza, il catalogo ha molto struttura semplice, costituito da due parti: un numero di inode e un nome.

Organizzazione fisica di ext2

Struttura delle partizioni del disco

Come parte di ext2, si può distinguere quanto segue:

  • blocchi e gruppi di blocchi;
  • inodo;
  • superblocco.

L'intero spazio della partizione del disco è suddiviso in blocchi di dimensione fissa, i blocchi essendo un multiplo della dimensione del settore (1024, 2048, 4096 o 8192 byte). La dimensione del blocco viene specificata durante la creazione di un file system su una partizione del disco. A tutti i blocchi vengono assegnati numeri di serie. Per ridurre la frammentazione e il movimento della testa disco rigido durante la lettura di array di dati di grandi dimensioni, i blocchi vengono combinati in gruppi.

Il concetto di base di un file system è un inode (chiamato anche inode - nodo informativo). Si tratta di una struttura speciale contenente informazioni sugli attributi e sulla posizione fisica del file. I decryptor dell'indice sono combinati in una tabella contenuta all'inizio di ogni gruppo di blocchi. Il superblocco è l'elemento principale del file system ext2. Contiene informazioni generali sul file system. Il superblocco si trova a 1024 byte dall'inizio della sezione. L'integrità del superblocco determina l'integrità del file system. Il sistema operativo crea diverse copie di backup del superblocco, nel caso in cui la partizione sia danneggiata. Il blocco successivo dopo il superblocco contiene una tabella descrittiva globale: una descrizione dei gruppi di blocchi sotto forma di un array con informazioni generali su tutti i gruppi di blocchi.

Gruppo di blocco

Tutti i blocchi su una partizione ext2 sono divisi in gruppi. Viene creata una voce separata per ciascun gruppo nella tabella dei descrittori globali. Questa voce memorizza i parametri di base, come: il numero di blocco in bitmap e tabelle, il numero di blocchi liberi nel gruppo, il numero di inode contenenti directory.

Blocco bitmapè un sistema in cui ogni bit informa se il blocco ad esso corrispondente è assegnato a un file. Se il bit è 1, allora il blocco è occupato. Una bitmap inode svolge una funzione simile: mostra quali inode sono occupati e quali no. Il kernel Linux tenta di distribuire uniformemente gli inode di directory in gruppi e sposta gli inode di file nel gruppo con la directory principale. Tutto lo spazio rimanente, che appare nella tabella come dati, viene allocato per l'archiviazione dei file.

Sistema di indirizzamento dati

Il sistema di indirizzamento dei dati è uno dei componenti più seri e chiave del file system. Grazie ad esso, il file desiderato si trova tra i tanti blocchi vuoti o occupati del disco.

ext2 utilizza il seguente schema di indirizzamento dei blocchi di file. Per memorizzare l'indirizzo del file, vengono assegnati 15 campi, ciascuno dei quali è composto da 4 byte. Se il file rientra in 12 blocchi, i numeri dei cluster corrispondenti vengono elencati nei primi dodici campi dell'indirizzo. Se la dimensione del file supera i 12 blocchi, il campo successivo contiene l'indirizzo del cluster in cui possono essere posizionati i numeri dei blocchi successivi del file. Pertanto, il tredicesimo campo viene utilizzato per l'indirizzamento indiretto.

Con una dimensione massima del blocco di 4096 byte, il cluster corrispondente al 13° campo può contenere fino a 1024 numeri di blocco successivo nel file. Se la dimensione del file supera 12+1024 blocchi, viene utilizzato il 14° campo, che contiene l'indirizzo di un cluster contenente 1024 numeri di cluster, ciascuno dei quali fa riferimento a 1024 blocchi del file. Qui viene utilizzato il doppio indirizzamento indiretto. E se il file include più di 12 + 1024 + 1048576 blocchi, l'ultimo 15° campo viene utilizzato per l'indirizzamento indiretto triplo.

Un tale sistema di indirizzamento consente, con una dimensione massima del blocco di 4096 byte, di avere file di dimensioni superiori a 2 TB.

Considera la struttura logica del file system ext2fs. Fisicamente HDD suddiviso in settori di 512 byte. Il primo settore di una partizione del disco in qualsiasi file system è considerato l'area di avvio. Nella partizione primaria, quest'area contiene una voce di avvio, un pezzo di codice che avvia il processo di avvio del sistema operativo all'avvio. Quest'area non è utilizzata su altre sezioni. I restanti settori sono combinati in blocchi logici di 1, 2 o 4 kilobyte. Un blocco logico è il più piccolo blocco di dati indirizzabile: i dati di ogni file occupano un numero intero di blocchi. I blocchi, a loro volta, vengono combinati in gruppi di blocchi. I gruppi di blocchi e i blocchi all'interno di un gruppo sono numerati in sequenza, a partire da 1.

Le strutture dati utilizzate quando si lavora con il file system ext2fs sono descritte nel file di intestazione /usr/include/linux/ext2fs .h.

Il superblocco funge da punto di partenza del file system e memorizza tutto

informazioni su di lei. Ha una dimensione di 1024 byte e si trova a un offset di 1024 byte dall'inizio del file system. In ogni gruppo di blocchi viene duplicato, il che consente di ripristinarlo rapidamente dopo i guasti. Il superblocco determina la dimensione del file system, il numero massimo di file nella partizione, la quantità di spazio libero e contiene informazioni su dove cercare le aree non allocate. All'avvio del sistema operativo, il superblocco viene letto in memoria e tutte le modifiche al file system vengono prima riflesse nella copia del superblocco situata nel sistema operativo e vengono scritte su disco solo periodicamente. Ciò migliora le prestazioni del sistema perché molti utenti e processi aggiornano costantemente i file. D'altra parte, quando il sistema è fermo, il superblocco deve essere scritto su disco, il che non consente di spegnere il computer semplicemente spegnendo l'alimentazione. In caso contrario, al successivo avvio, le informazioni registrate nel sunerblock non saranno

corrispondente allo stato effettivo del file system.

La descrizione (descrittore) del gruppo di blocchi segue il superblocco. Le informazioni memorizzate in esso consentono di trovare bitmap di blocchi e inode, nonché una tabella di inode.

Una bitmap di blocco è una struttura, ogni bit della quale indica se un blocco con lo stesso numero è assegnato a un file. Un valore pari a 1 indica che il blocco è occupato. Questa mappa viene utilizzata per cercare blocchi liberi nei casi in cui è necessario allocare spazio per un file..

La bitmap inode svolge una funzione simile alla tabella degli inode: mostra quali inode sono occupati.

Ogni file ha uno e un solo inode (inode, i-node, nodo informativo), che è identificato dal suo numero di serie - l'indice del file. L'inode contiene i metadati del file. Tra questi ci sono tutti gli attributi del file, ad eccezione del suo nome, e un puntatore ai dati del file.

Per un normale file o directory, questo puntatore è un array di 15 indirizzi di blocco. I primi 12 indirizzi in questo array sono collegamenti diretti ai numeri di blocco in cui sono archiviati i dati del file. Se i dati non rientrano in 12 blocchi, viene attivato il meccanismo di indirizzamento indiretto. L'indirizzo successivo in questo array è un collegamento indiretto, ovvero l'indirizzo di un blocco che memorizza un elenco di indirizzi dei blocchi successivi con i dati di questo file.

Quanti blocchi di dati possono essere indirizzati in questo modo? L'indirizzo del blocco occupa 4 byte, il blocco, come già accennato, è di 1, 2 o 4 kilobyte. Ciò significa che è possibile posizionare da 256 a 1024 blocchi mediante indirizzamento indiretto.

E se il file è ancora più lungo? L'indirizzo successivo nell'array di puntatori punta al blocco del doppio indirizzamento. (doppio blocco indiretto). Questo blocco contiene un elenco di indirizzi di blocco, che a loro volta contengono elenchi di indirizzi dei successivi blocchi dati.

Infine, l'ultimo indirizzo nell'array di puntatori specifica l'indirizzo di un blocco a triplo indirizzamento, ovvero un blocco con un elenco di indirizzi di blocco che sono blocchi a doppio indirizzamento.

Finora, non è chiaro dove si trovi il nome del file se non è né tra i dati del file né tra i suoi metadati. Nei sistemi UNIX-like, il nome del file non è un attributo del file stesso, ma del file system, inteso come struttura logica di directory. Il nome del file viene memorizzato solo nella directory a cui è assegnato il file e da nessun'altra parte. Ne derivano curiose conseguenze.

Innanzitutto, qualsiasi numero di nomi assegnati a diverse directory può corrispondere a un inode e sono tutti reali. Il numero di nomi (hard link) viene conteggiato nell'inode. Questo è l'importo che puoi vedere con il comando Is -1.

In secondo luogo, eliminare un file significa semplicemente eliminare la sua voce dai dati della directory e diminuire il conteggio dei collegamenti di 1.

In terzo luogo, un nome può essere abbinato solo a un numero di inode all'interno dello stesso file system, motivo per cui non è possibile creare un collegamento fisico a un altro file system (simbolico: è possibile, ha un meccanismo di archiviazione diverso).

Allo stesso modo, la directory stessa è assegnata alla sua directory principale. La directory root viene sempre scritta nell'inode numero 2 (il numero 1 è riservato all'elenco di indirizzi dei blocchi danneggiati). Ogni directory memorizza un collegamento a se stessa e alla sua directory principale: queste sono le pseudo-sottodirectory "." E "..".

Pertanto, il numero di collegamenti a una directory è uguale al numero delle sue sottodirectory più due.

I dati della directory sono un elenco collegato con voci di lunghezza variabile e hanno un aspetto simile a questo:

Struttura delle directory in ext2fs

E i file del dispositivo fisico? Possono trovarsi nelle stesse directory dei normali file: non ci sono dati nella directory che indichino se il nome appartiene a un file su disco oa un dispositivo. La differenza è a livello di inode. Se l'i-node di un file normale punta ai blocchi del disco in cui sono archiviati i suoi dati, allora l'i-node del file di dispositivo contiene un puntatore all'elenco dei driver di dispositivo nel kernel, l'elemento dell'elenco che corrisponde al numero di dispositivo principale:

Differenza tra file normale e file dispositivo

Proprietà del file system ext2fs:

La dimensione massima del file system è di 4 TB.

La dimensione massima del file è di 2 GB.

La lunghezza massima di un nome file è di 255 caratteri.

La dimensione minima del blocco è di 1024 byte.

Il numero di inode allocati è 1 per 4096 byte della partizione.

VLADIMIRO MESHKOV

architettura del file system ext2

L'articolo discute la struttura logica di ext2, il file system del sistema operativo Linux.

Componenti di base di un file system ext2

Come in qualsiasi file system UNIX, nel file system ext2 si possono distinguere i seguenti componenti:

  • blocchi e gruppi di blocchi;
  • nodo informativo (nodo informativo);
  • superblocco.

Blocchi e gruppi di blocchi

L'intero spazio della partizione del disco è suddiviso in blocchi di dimensione fissa, multipli della dimensione del settore: 1024, 2048 e 4096 byte. La dimensione del blocco viene specificata durante la creazione di un file system su una partizione del disco rigido. Una dimensione di blocco più piccola consente di risparmiare spazio su disco rigido, ma limita anche la dimensione massima del file system. Tutti i blocchi hanno numeri di serie. Per ridurre la frammentazione e il numero di movimenti della testina del disco rigido durante la lettura di grandi array di dati, i blocchi vengono combinati in gruppi.

Nodo informativo

Il concetto di base di un file system è un nodo di informazioni, un nodo di informazioni o un inode. Questa è una struttura speciale che contiene informazioni sugli attributi e sulla posizione fisica di un file. Gli attributi del file sono il tipo (file normale, directory, ecc.), i diritti di accesso ad esso, l'ID del proprietario, le dimensioni, l'ora di creazione. Le informazioni sulla posizione fisica sono una sequenza di numeri di blocco assoluti contenenti i dati del file.

Superblocco

Il superblocco è l'elemento principale del file system ext2. Contiene le seguenti informazioni sul file system (l'elenco non è completo):

  • il numero totale di blocchi e inode nel file system;
  • il numero di blocchi e inode liberi nel file system;
  • dimensione del blocco del file system;
  • il numero di blocchi e inode nel gruppo;
  • dimensione dell'inode;
  • identificatore del file system;
  • numero del primo blocco dati.

In altre parole, questo è il numero del blocco contenente il superblocco. Questo numero è sempre 0 se la dimensione del blocco del file system è maggiore di 1024 byte e 1 se la dimensione del blocco è 1024 byte.

La salute del file system dipende direttamente dall'integrità del superblocco. Il sistema operativo crea diverse copie di backup del superblocco in modo che possa essere ripristinato in caso di danneggiamento. La copia master si trova all'offset 1024 byte dall'inizio della partizione su cui è stato creato il file system (i primi 1024 byte sono riservati al caricatore del sistema operativo).

Le prime versioni del filesystem ext2 creavano copie superblocco all'inizio di ogni gruppo di blocchi. Ciò ha comportato grosse perdite. spazio sul disco, quindi in seguito il numero di backup del superblocco è stato ridotto e sono stati assegnati i gruppi di blocchi 0, 1, 3, 5 e 7 per accoglierli.

Formato del gruppo di blocchi

Un diagramma a blocchi generalizzato del file system ext2 è mostrato in fig. 1.

Quasi tutti i gruppi di blocchi hanno lo stesso formato. In ogni gruppo, oltre ai blocchi di informazioni, vengono memorizzate informazioni sull'occupazione di blocchi e inode del gruppo sotto forma di bitmap. Il gruppo di blocchi 0 include anche un super blocco e una tabella dei descrittori di gruppo, di cui parleremo di seguito.

La bitmap block busy si trova in genere nel primo blocco del gruppo. Se nel gruppo è presente un superblocco di backup, la bitmap si trova nel secondo blocco del gruppo. La dimensione della bitmap è di un blocco. Ogni bit di questa mappa indica lo stato del blocco. Se il bit è settato (1) allora il blocco è occupato, se è resettato (0) il blocco è libero. Il primo blocco del gruppo corrisponde al bit zero della mappa, il secondo blocco corrisponde al primo bit e così via.

Gli inode che si trovano all'interno dello stesso gruppo vengono raccolti in una tabella. Nella bitmap di occupazione degli inode di un gruppo, ogni bit rappresenta lo stato di un elemento nella tabella degli inode del gruppo.

Ciascun gruppo di blocchi è descritto da un descrittore di gruppo di blocchi. Un descrittore di gruppo è una struttura che contiene informazioni sugli indirizzi della bitmap di blocco occupato, bitmap di inode occupato e tabella di inode del gruppo corrispondente. Tutti i descrittori di gruppo sono raccolti in una tabella dei descrittori di gruppo, che è memorizzata nel gruppo di blocchi 0. Come per il superblocco, sistema operativo crea backup tabelle dei descrittori di gruppo.

Algoritmo di lettura dei file

Ogni inode, come un blocco, ha un numero di sequenza univoco all'interno del file system e contiene informazioni su un solo file. Pertanto, per accedere al contenuto di un file, è necessario conoscere il numero ordinale dell'inode ad esso corrispondente.

Come accennato in precedenza, le informazioni sulla posizione fisica del file sono contenute nell'inode. Queste informazioni sono una sequenza di numeri di blocco a 32 bit contenenti i dati del file (Figura 1). I primi 12 numeri sono collegamenti diretti a blocchi di informazioni (numero di blocchi diretti). Il 13° numero è un numero di blocco indiretto. Contiene l'indirizzo del blocco, che memorizza gli indirizzi dei blocchi di informazioni. Il 14° numero è un doppio collegamento indiretto (doppio numero di blocchi), il 15° numero è un triplo collegamento indiretto (triplo numero di blocchi).

Il nome del file non fa parte dell'inode, la mappatura tra nomi di file e numeri di sequenza di inode viene eseguita tramite directory.

Cataloghi

I file sui sistemi UNIX e POSIX sono archiviati in un file system gerarchico ad albero. La radice del file system è la directory radice, indicata dal simbolo "/". Ogni nodo intermedio nell'albero del file system è una directory. I nodi foglia dell'albero del filesystem sono directory o file vuoti. Il percorso assoluto di un file è costituito dai nomi di tutte le directory che conducono al file specificato, a partire dalla directory principale. Ad esempio, il percorso /home/test.file indica che il file test.file si trova nella directory home, che a sua volta si trova nella directory root "/".

Una directory, come un file, è descritta con un inode. Il contenuto di una directory è un array di voci, ciascuna contenente informazioni su un file che si trova "all'interno" della directory corrente.

La voce della rubrica ha il seguente formato:

  • il numero di inode del file;
  • lunghezza record in byte;
  • nome del file;
  • lunghezza del nome file.

La ricerca del numero di inode di un file inizia sempre dalla directory principale. Ad esempio, per ottenere il numero di inode di un file che si trova nella directory principale, il sistema operativo deve ottenere il contenuto della directory principale, trovare una voce in essa con il nome di questo file ed estrarre il numero di inode del file da questa voce.

I primi inode sono riservati dal file system e sono elencati nel file di intestazione:

*Numeri di inode speciali

#define EXT2_BAD_INO 1 /* Inode blocchi danneggiati */

#define EXT2_ROOT_IN 2 /* Inode radice */

#define EXT2_ACL_IDX_IN 3 /* inode ACL */

#define EXT2_ACL_DATA_INO 4 /* inode ACL */

#define EXT2_BOOT_LOADER_INO 5 /* Inode del caricatore di avvio */

#define EXT2_UNDEL_DIR_INO 6 /* Annulla l'eliminazione dell'inode della directory */

L'inode numero 2 (root inode) è riservato alla voce della directory root. Questo inode è nel gruppo di blocchi 0 ed è la seconda posizione nella tabella degli inode del gruppo. Il numero del primo inode non riservato è memorizzato nel superblocco.

Dopo aver determinato il numero di sequenza dell'inode del file, il kernel calcola il numero del gruppo in cui si trova questo inode e la sua posizione nella tabella degli inode del gruppo. Leggendo da questa posizione dell'inode, il sistema operativo ottiene informazioni complete sul file, inclusi gli indirizzi dei blocchi in cui è memorizzato il contenuto del file.

Il numero del gruppo di blocchi in cui si trova l'inode viene calcolato dalla formula:

gruppo = (inode_num - 1) / inodes_per_group

Dove:

  • gruppo– numero del gruppo di blocchi desiderato;
  • inode_num– numero di sequenza dell'inode che definisce il file;
  • inodes_per_group– il numero di inode nel gruppo (questa informazione è nel superblocco).

La posizione dell'inode nella tabella degli inode del gruppo è determinata dalla formula:

index = (inode_num - 1) % inodes_per_groupe

dove index è la posizione dell'inode nella tabella.

Si consideri un esempio di recupero del contenuto del file test.file che si trova nella directory principale. Per leggere il file /test.file, è necessario:

  • trova una voce su questo file nell'array di voci nella directory principale;
  • estrarre il numero di sequenza dell'inode del file, calcolare il numero del gruppo in cui si trova questo inode;
  • estrarre l'indirizzo della tabella inode del gruppo dal descrittore del gruppo;
  • calcolare la posizione dell'inode in questa tabella;
  • leggere l'inode di un file;
  • estrarre gli indirizzi dei blocchi di informazioni dall'inode e leggere le informazioni contenute in questi blocchi.

Sulla fig. La Figura 2 mostra i passaggi per leggere il /test.file in dettaglio.

    Passaggi 1-6 - lettura della directory principale:

  1. Dal gruppo di blocchi 0 viene letta la tabella dei descrittori di gruppo.
  2. Il descrittore del gruppo di blocchi 0 viene recuperato dalla tabella dei descrittori del gruppo e da essa viene letto l'indirizzo della tabella degli inode del gruppo 0.
  3. La tabella degli inode viene letta dal gruppo di blocchi 0.
  4. L'inode della directory root è fissato a 2, quindi il secondo elemento viene letto dalla tabella degli inode del gruppo 0, che contiene l'indirizzo del blocco che contiene il contenuto della directory root. Supponiamo che questo blocco si trovi nel gruppo di blocchi A.
  5. Dal gruppo di blocchi A viene letto il blocco contenente le voci della directory principale.
  6. Viene cercata la voce denominata "test.file". Se viene trovata una voce di questo tipo, da essa viene recuperato il numero di inode di "test.file".
  7. Specificando il numero di inode, è possibile accedere ai blocchi di informazioni del file (passaggi 7-11):

  8. Vengono calcolati il ​​numero del gruppo in cui si trova l'inode dato e la sua posizione nella tabella degli inode del gruppo (assumendo che il numero del gruppo sia B e la posizione nella tabella sia X).
  9. Dalla tabella dei descrittori di gruppo, recuperiamo il descrittore del gruppo di blocchi B e da esso leggiamo l'indirizzo della tabella degli inode di questo gruppo di blocchi.
  10. La tabella degli inode viene letta dal gruppo di blocchi B.
  11. Dalla tabella degli inode del gruppo di blocchi B, viene letto l'inode in posizione X.
  12. Dall'inode read vengono estratti gli indirizzi del blocco con il contenuto del file /test.file e le informazioni vengono lette dal blocco con l'indirizzo specificato.

Implementazione software dell'algoritmo di lettura dei file

Dati iniziali: esiste una partizione del disco rigido su cui viene creato il file system ext2. Questa partizione corrisponde al file di dispositivo /dev/hda3. La sottodirectory home è stata creata nella directory principale della partizione e contiene il file test.file con il seguente contenuto:

Gli agrumi vivrebbero nei boschetti del sud?

Sì, ma una copia falsa!

1234567890-=

Non pensare male, questa non è una sciocchezza, ma un esercizio di prova del corso di formazione per operatori telegrafici nelle truppe di segnalazione dell'ex Unione Sovietica!

Attenzione! Uno dovrebbe prendere in considerazione punto importante. Il file creato non verrà scritto immediatamente sul disco, ma andrà prima nel buffer del disco. Un tentativo di ottenere immediatamente il contenuto del file utilizzando l'algoritmo di cui sopra non porterà a nulla, poiché non ci sono informazioni su questo file fisicamente sul disco. È necessario "forzare" il sistema a scrivere il buffer del disco su disco. Il modo più semplice per farlo è eseguire un'operazione di riavvio. Pertanto, dopo aver creato il file, riavviare il sistema.

Il nostro compito è utilizzare il file del dispositivo /dev/hda3 per leggere il file /home/test.file accedendo direttamente ai suoi blocchi di informazioni.

Si consideri l'implementazione software del modulo che esegue questa operazione.

File di intestazione:

#includere

#includere

#includere

#includere

#includere

#includere

Il file di intestazione definisce i tipi strutturali che descrivono i componenti principali del file system ext2: superblocco, descrittore di gruppo di blocchi, nodo di informazioni, voce di directory.

Consideriamo brevemente i campi inclusi in ciascuna di queste strutture:

  1. Struttura del superblocco struct ext2_super_block:
    • __u32 s_inodes_countè il numero totale di inode nel file system;
    • __u32 s_blocks_countè il numero totale di blocchi nel file system;
    • __u32 s_free_blocks_count– numero di blocchi liberi;
    • __u32 s_free_inodes_count– numero di inode liberi;
    • __u32 s_first_data_block– numero del primo blocco dati (numero del blocco in cui si trova il superblocco);
    • __u32 s_log_block_size- Questo valore viene utilizzato per calcolare la dimensione del blocco. La dimensione del blocco è determinata dalla formula: dimensione del blocco = 1024<< s_log_block_size;
    • __u32 s_blocchi_per_gruppo– il numero di blocchi nel gruppo;
    • __u32 s_inodes_per_group– numero di inode nel gruppo;
    • __u16 s_magia– identificatore del file system ext2 (firma 0xEF53);
    • __u16 s_inode_size– dimensione del nodo informativo (inode);
    • __u32s_first_inoè il numero del primo inode non riservato.
  2. Struttura del descrittore del gruppo di blocchi struct ext2_group_desc:
    • __u32 bg_block_bitmap– bitmap dell'occupazione del blocco di gruppo;
    • __u32 bg_inode_bitmap– gruppo inode occupato bitmap;
    • __u32 bg_inode_table– l'indirizzo della tabella inode del gruppo.
  3. Struttura del nodo informazioni struct ext2_inode:
    • __u16 i_mode - tipo di file e diritti di accesso ad esso. Il tipo di file è determinato dai bit 12-15 di questo campo:
      • 0xA000– legame simbolico;
      • 0x8000– fascicolo regolare;
      • 0x6000– file dispositivo a blocchi;
      • 0x4000– elenco;
      • 0x2000– file dispositivo caratteri;
      • 0x1000– Canale FIFO.
    • __u32 i_size– dimensione in byte;
    • __u32 i_atime– ora dell'ultimo accesso al file;
    • __u32 i_ctime– ora di creazione del file;
    • __u32 i_mtime– ora dell'ultima modifica;
    • __u32 i_blocchi– il numero di blocchi occupati dal file;
    • __u32 i_blocco– indirizzi di blocchi informativi (compresi tutti i riferimenti indiretti).
  4. Il valore di EXT2_N_BLOCKS è definito nel file:

    * Costanti relative ai blocchi dati

    #define EXT2_NDIR_BLOCKS 12

    #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS

    #define EXT2_DIND_BLOCK (EST2_IND_BLOCK + 1)

    #define EXT2_TIND_BLOCK (EST2_DIND_BLOCK + 1)

    #define EXT2_N_BLOCCHI(EST2_TIND_BLOCCO + 1)

  5. Struttura della voce di directory struct ext2_dir_entry_2:
  6. #define EXT2_NAME_LEN 255

  • __u32 inode– numero inode del file;
  • __u16 rec_len– lunghezza della voce di rubrica;
  • __u8 nome_len– lunghezza del nome del file;
  • nome del personaggio nome del file.

Determiniamo il nome della partizione su cui è stato creato il file system, le strutture globali e le variabili.

#define NOME_PARTE "/dev/hda3"

struct ext2_super_block sb;

/* buffer per memorizzare la tabella dei descrittori di gruppo */

carattere senza segno buff_grp;

buff di caratteri non firmato; /* buffer delle informazioni */

int indev; /* descrittore del file del dispositivo */

int BLKSIZE; /* dimensione del blocco del filesystem */

Definiamo alcune funzioni di cui abbiamo bisogno per lavorare:

Funzione di lettura del superblocco:

void read_sb()

memset(&sb,0,1024);

Spostiamo 1024 byte dall'inizio della sezione e leggiamo il superblocco nella struttura struct ext2_super_block sb:

If(lseek(indev,1024,0)< 0) {

errore("cerca");

Esci(-1);

If(read(indev,(char *)&sb,sizeof(sb))< 0) {

errore("leggere");

Esci(-1);

Verifica dell'ID del file system:

If(sb.s_magic != EXT2_SUPER_MAGIC) (

Printf("Tipo di file system sconosciuto!");

Esci(-1);

Il valore EXT2_SUPER_MAGIC è definito nel file di intestazione.

Mostriamo informazioni sul file system che si trova nel superblocco:

printf(" Informazioni superblocco ----------- ");

Printf("Conteggio inode - %u ",sb.s_inodes_count);

Printf("Conteggio blocchi - %u ",sb.s_blocks_count);

Printf("Dimensione blocco - %u",1024<< sb.s_log_block_size);

Printf("Primo inode - %d ",sb.s_first_ino);

Printf("Magia - 0x%X ",sb.s_magia);

Printf("Dimensione inode - %d ",sb.s_inode_size);

Printf("Inode per gruppo - %u ",sb.s_inodes_per_group);

Printf("Blocchi per gruppo - %u ",sb.s_blocks_per_group);

Printf("Primo blocco dati - %u ",sb.s_first_data_block);

ritorno;

Funzione di lettura della tabella dei descrittori di gruppo:

void read_gdt()

Calcola la dimensione del blocco del file system:

BLKSIZE = 1024<< sb.s_log_block_size

La tabella dei descrittori di gruppo si trova nel blocco immediatamente successivo al primo blocco di dati (dietro il superblocco).

Leggendo la tabella:

If(lseek(indev, (sb.s_first_data_block + 1) * BLKSIZE, 0)< 0) {

errore("cerca");

Esci(-1);

If(read(indev,buff_grp,BLKSIZE)< 0) {

errore("leggere");

Esci(-1);

ritorno;

La funzione per ottenere il contenuto di un inode dal suo numero:

void get_inode(int inode_num, struct ext2_inode *in)

I parametri di input della funzione sono il numero di inode e la struttura struct ext2_inode.

Struct ext2_group_desc gd;

gruppo U64, indice, pos;

Calcoliamo il numero del gruppo di blocchi in cui si trova l'inode con il numero ordinale inode_num:

Gruppo = (inode_num - 1) / sb.s_inodes_per_group;

Estrai il descrittore di gruppo dalla tabella dei descrittori di gruppo e copialo nella struttura struct ext2_group_desc gd:

Memset((void *)&gd, 0, sizeof(gd));

Memcpy((void *)&gd, buff_grp + (group * (sizeof(gd))), sizeof(gd));

Calcoliamo la posizione dell'inode con il numero ordinale inode_num nella tabella degli inode del gruppo group e leggiamo questo inode nella struttura struct ext2_inode:

index = (inode_num - 1) % sb.s_inodes_per_group;

Pos = ((__u64)gd.bg_inode_table) * BLKSIZE + (indice * sb.s_inode_size);

Preread64(indev, in, sb.s_inode_size, pos);

ritorno;

Funzione di lettura blocco dati:

void read_iblock(struct ext2_inode *in, int blk_num)

U64pos;

I parametri di input della funzione sono la struttura dell'inode e il numero di blocco (ovvero il numero dalla sequenza di blocchi di indirizzi situati nell'inode).

Calcoliamo l'offset al blocco di informazioni sulla partizione e leggiamo questo blocco nel buffer buff globale:

Pos = ((__u64)in->i_block) * BLKSIZE;

Preread64(indev, buff, BLKSIZE, pos);

ritorno;

La funzione per ottenere il contenuto della directory principale:

void get_root_dentry()

Struct ext2_inode in;

Il numero di inode della directory root è noto, quindi otteniamo il contenuto dell'inode della directory root e ne leggiamo il contenuto nel buffer buff:

get_inode(EXT2_ROOT_INO, &in);

Read_iblock(&in, 0);

Il buffer buff conterrà il contenuto della directory principale.

ritorno;

Funzione per ottenere il numero di inode dal nome del file:

int get_i_num(char *nome)

I parametri di input della funzione sono il nome del file. Il valore restituito è il numero di inode del file.

int i = 0, rec_len = 0;

Struct ext2_dir_entry_2dent;

Il buff buffer contiene un array di voci di directory. Per determinare il numero di inode di un file, devi trovare una voce in questo array con il nome di questo file:

Per(;i< 700; i++) {

Memcpy((void *)&dent, (buff + rec_len), sizeof(dent));

If(!memcmp(dent.name, name, dent.name_len)) break;

Rec_len += dent.rec_len;

Ritorna dent.inode;

Ora scriviamo la funzione principale:

int principale()

Variabili e strutture:

struct ext2_inode in;

// percorso assoluto del file

Carattere non firmato *full_path = "/home/test.file";

carattere senza segno buff1;

Int statico i = 1;

int n, i_num, outf, tipo;

Il primo carattere in un percorso assoluto di un file deve essere una barra (/). Controlliamolo:

If(percorso_completo != "/") (

errore("barra");

Esci(-1);

Apri il file del dispositivo, leggi la tabella dei descrittori del superblocco e del gruppo:

indev = open(PART_NAME,O_RDONLY);

se (ind< 0) {

errore("apri");

Esci(-1);

Leggi_sb();

Leggi_gdt();

Ottieni il contenuto della directory principale:

get_root_dentry();

Il buff buffer ora contiene tutte le voci nella directory principale (puoi salvarle in un file separato se lo desideri). Ora che abbiamo le voci della directory principale, possiamo accedere al contenuto di test.file usando l'algoritmo di lettura del file sopra. A tal fine, organizziamo un ciclo. Nel corpo del ciclo, analizzeremo il nome del percorso assoluto del file, evidenziandone gli elementi: sottodirectory (ne abbiamo una, home) e il nome del file desiderato (test.file). Per ogni elemento, determiniamo il numero ordinale dell'inode, leggiamo questo inode e quindi otteniamo il contenuto del blocco zero (dalla sequenza di blocchi di indirizzi situati nell'inode):

mentre(1) (

memset(buff1,0,sizeof(buff1));

Per(n = 0 ; n< EXT2_NAME_LEN; n++, i++) {

Buff1[n] = percorso_completo[i];

If((buff1[n] == "/") || (buff1[n] == "?")) (

io++;

rottura;

buff1[n] = "?";

Per ogni elemento del percorso assoluto del file, determiniamo il numero di sequenza dell'inode, leggiamo questo inode in memoria e quindi otteniamo il contenuto del blocco zero:

I_num = get_i_num(buff1);

Get_inode(i_num, &in);

Read_iblock(&in, 0);

Visualizziamo le informazioni sul file (nome, numero di inode, dimensione e tipo di file):

Printf("Numero inode - %u ", i_num);

Printf("Nome file - %s ", buff1);

Printf("Dimensione file - %u ",in.i_size);

Il tipo di file è determinato dai quattro bit superiori del campo i_mode della struttura struct ext2_inode:

tipo = ((in.i_mode & 0xF000) >> 12);

Printf("Tipo - %d ",tipo);

interruttore (tipo) (

Caso(0x04):

Printf("(cartella)");

rottura;

Caso(0x08):

Printf("(file normale)");

rottura;

Caso(0x06):

Printf("(file dispositivo a blocchi)");

rottura;

Caso(0x02):

Printf("(file dispositivo char) ");

rottura;

predefinito:

Printf("(tipo sconosciuto)");

rottura;

Controllo del tipo di file. Se questo è un file normale, interrompiamo il ciclo:

If(tipo & 0x08) (

Il buff buffer conterrà le informazioni lette dai blocchi di informazioni del file /home/test.file. Scriviamo queste informazioni in un file:

Outf = open("out",O_CREAT|O_RDWR,0600);

Write(outf, buff, sizeof(buff));

chiudere(outf);

rottura;

Uscita:

chiudi(indev);

ritorno 0;

Questo conclude la nostra considerazione sulla struttura logica del file system ext2.

Descriveremo ora il più popolare file system su disco di Linux, ext2. La prima versione di Linux utilizzava il file system MINIX 1, che aveva nomi di file brevi e una dimensione massima del file di 64 MB. Il file system MINIX 1 è stato infine sostituito dal primo file system esteso, ext, che consentiva nomi di file più lunghi e dimensioni di file maggiori. A causa della sua bassa efficienza (in termini di prestazioni), il sistema ext è stato sostituito dal suo successore ext2, che è ancora ampiamente utilizzato oggi.

La partizione del disco con ext2 contiene il file system mostrato in fig. Disposizione 10.17. Il blocco 0 non è utilizzato dal sistema Linux e contiene il codice di avvio del computer. Dopo il blocco 0, la partizione del disco viene divisa in gruppi di blocchi (ignorando i limiti del cilindro del disco). Ogni gruppo è organizzato come segue.


Il primo blocco è il superblocco, che memorizza le informazioni sul layout del file system, incluso il numero di i-node, il numero di blocchi del disco, l'inizio dell'elenco dei blocchi del disco liberi (di solito diverse centinaia di elementi). Questo è seguito da un descrittore di gruppo contenente informazioni sulla posizione delle bitmap, il numero di blocchi e i-node liberi nel gruppo e il numero di directory nel gruppo. Questa informazione è importante perché il filesystem ext2 tenta di distribuire le directory uniformemente sul disco.

Le due bitmap tengono traccia dei blocchi liberi e degli i-nodi liberi (anche questo è ereditato dal file system MINIX 1 e lo distingue dalla maggior parte dei file system UNIX, che usano un elenco per i blocchi liberi). La dimensione di ogni bitmap è di un blocco. Con una dimensione del blocco di 1 KB, questo schema limita la dimensione del gruppo di blocchi a 8192 blocchi e 8192 i-node. Il primo numero è un limite reale e il secondo è praticamente nessuno. Con blocchi da 4 KB, i numeri sono quattro volte più grandi.

Quindi vengono individuati gli i-node stessi. Sono numerati da 1 a un massimo. Ogni i-node ha una dimensione di 128 byte e descrive esattamente un file. L'i-node contiene informazioni sull'account (incluso tutto ciò che viene restituito dalla chiamata stat, che le prende semplicemente dall'i-node), oltre a informazioni sufficienti per individuare tutti i blocchi del disco che contengono dati di file.

Gli i-node sono seguiti da blocchi di dati. Tutti i file e le directory sono memorizzati qui. Se un file o una directory è costituito da più di un blocco, non è necessario che tali blocchi siano contigui sul disco. Infatti i blocchi file grandeè probabile che siano sparsi su tutto il disco.

Gli i-node corrispondenti alle directory sono sparsi in tutti i gruppi di blocchi del disco. Ext2 tenta di posizionare i file regolari nello stesso gruppo di blocchi della directory principale e i file di dati nello stesso blocco dell'i-node del file sorgente (supponendo che vi sia spazio sufficiente). Questa idea è stata presa in prestito dal Berkeley Fast File System (McKusick et al., 1984). Le bitmap vengono utilizzate per ricevere Soluzioni veloci per quanto riguarda la selezione

posizioni per i nuovi dati del file system.

Quando vengono allocati nuovi blocchi di file, ext2 prealloca anche alcuni (otto) blocchi aggiuntivi per lo stesso file (per ridurre al minimo la frammentazione del file dovuta a scritture future). Questo schema distribuisce il file system su tutto il disco. Ha anche buone prestazioni (grazie alla sua natura contigua e alla ridotta frammentazione).

Per accedere a un file, devi prima utilizzare una delle chiamate di sistema di Linux (come open), che richiede di specificare il percorso del file. Questo percorso viene analizzato e le sue directory costituenti vengono estratte da esso. Se viene specificato un percorso relativo, la ricerca inizia dalla directory corrente del processo, altrimenti dalla directory principale. In ogni caso, l'i-node per la prima directory è facile da trovare: c'è un puntatore ad esso nel descrittore del processo, oppure (nel caso della directory root) è memorizzato in un blocco specifico su disco.

La directory consente nomi di file lunghi fino a 255 caratteri (Figura 10.18). Ogni directory è composta da un numero di blocchi di disco (in modo che la directory possa essere scritta su disco in modo atomico). In una directory, gli elementi per i file e le directory sono in ordine non ordinato (ogni elemento segue immediatamente il precedente). Gli elementi non possono attraversare i limiti dei blocchi, quindi di solito c'è una certa quantità di byte inutilizzati alla fine di ogni blocco del disco.


Ogni voce di directory in Fig. 10.18 è costituito da quattro campi a lunghezza fissa e un campo a lunghezza variabile. Il primo campo è il numero i-node, che è 19 per il file colossale, 42 per il file voluminoso e 88 per la directory bigdir. Poi viene il campo rec_len, che fornisce la dimensione dell'intera voce di directory in byte (possibilmente con ulteriori byte di riempimento dopo il nome). Questo campo è necessario per trovare la voce successiva (nel caso in cui il nome del file sia riempito con un numero sconosciuto di byte). Nella figura, questo campo è indicato da una freccia. Poi c'è un campo di tipo file, directory, ecc. L'ultimo campo di lunghezza fissa contiene la lunghezza del nome del file in byte (8, 10 e 6 per questo esempio). Infine, c'è il nome del file stesso, terminato da un byte nullo e riempito fino a un limite di 32 bit. Può essere seguito da ulteriori byte di riempimento.

Sulla fig. 10.18b mostra la stessa directory dopo che l'elemento per voluminoso è stato rimosso. Tutto ciò che viene fatto nella directory è aumentare il numero nel campo della dimensione del record. fascicolo precedente colossale e i byte di accesso alla directory per archivio remoto voluminose si trasformano in segnaposto per il primo record. Successivamente, questi byte possono essere utilizzati per la scrittura durante la creazione di un nuovo file.

Poiché le directory vengono cercate in modo lineare, può essere necessario molto tempo per trovare una voce che si trova alla fine di una directory di grandi dimensioni. Pertanto, il sistema conserva una cache delle directory a cui si è avuto accesso di recente. La ricerca nella cache viene eseguita in base al nome del file e, se viene trovata, la costosa ricerca lineare non è più necessaria. Un oggetto dentry viene inserito nella cache delle voci di directory per ciascuno dei componenti del percorso e (tramite il suo i-node) la directory viene cercata per le successive voci di percorso (fino a quando non viene trovato l'effettivo i-node del file).

Ad esempio, per trovare un file specificato da un percorso assoluto (come /usr/ast/file), è necessario seguire i seguenti passaggi. Prima di tutto, il sistema trova la directory root che di solito usa l'i-node numero 2 (soprattutto quando l'i-node numero 1 è riservato ai bad block). Mette la voce appropriata nella cache delle voci della directory (per future ricerche nella directory principale). Quindi cerca nella directory root la stringa "usr" per ottenere il numero i-node per la directory /usr (che viene anche inserita nella cache degli elementi della directory). Questo i-node viene quindi letto e da esso vengono estratti i blocchi del disco, in modo che la directory /usr possa essere letta e ricercata per la stringa "ast". Una volta trovata una voce corrispondente, è possibile determinare da essa il numero i-node per la directory /usr/ast. Dato questo numero i-node, può essere letto e possono essere trovati blocchi di directory. Infine, cerchiamo "file" e troviamo il suo numero i-node. Pertanto, l'utilizzo di un percorso relativo non solo è più conveniente per l'utente, ma riduce anche la quantità di lavoro per il sistema.

Se il file è presente, il sistema recupera il numero i-node e lo utilizza come indice della tabella i-node (su disco) per cercare l'i-node corrispondente e leggerlo in memoria. Questo i-node viene inserito nella tabella i-node, una struttura dati del kernel che contiene tutti gli i-node per aprire questo momento file e directory. Il formato dell'elemento i-node deve contenere (come minimo) tutti i campi restituiti dalla chiamata di sistema stat affinché la chiamata stat funzioni (vedere Tabella 10.10). A tavola. La Figura 10-13 mostra alcuni dei campi nella struttura i-node supportata dal file system Linux. L'effettiva struttura i-node contiene molti più campi, poiché la stessa struttura viene utilizzata per rappresentare directory, dispositivi e altri file speciali. La struttura i-node contiene anche campi riservati per usi futuri. La storia ha dimostrato che i bit inutilizzati non rimangono inattivi a lungo.

Ora vediamo come il sistema legge il file. Ricorda che una tipica chiamata di procedura di libreria per eseguire la chiamata di sistema read è simile a questa:

n = read(fd, buffer, nbyte);


Quando il kernel prende il controllo, tutto ciò con cui può iniziare sono questi tre parametri e le informazioni nelle sue tabelle interne (appartenenti all'utente). Uno degli elementi di queste tabelle interne è un array di descrittori di file. È indicizzato da descrittori di file e contiene un elemento per file aperto (fino a un numero massimo, solitamente 32 per impostazione predefinita).

L'idea è di iniziare da questo descrittore di file e terminare con il corrispondente bnode. Diamo un'occhiata a uno schema possibile: inserire un puntatore a un nodo in una tabella di descrittori di file. Nonostante la semplicità questo metodo(purtroppo) non funziona. Il problema è questo. Ogni descrittore di file deve avere un puntatore di file associato che specifica il byte nel file in cui inizierà la successiva operazione di lettura o scrittura. Dove dovrebbe essere memorizzato questo puntatore? Un'opzione è inserirla nella tabella dei nodi. Tuttavia, questo approccio non funzionerà se diversi processi non correlati aprono lo stesso file contemporaneamente, perché ogni processo deve avere il proprio puntatore.

La seconda soluzione consiste nel posizionare un puntatore nella tabella dei descrittori di file. Ogni processo che apre un file ha la propria posizione nel file. Sfortunatamente, anche questo schema non funziona, ma il motivo del fallimento lo è questo caso non così ovvio e legato alla natura condivisione file su un sistema Linux. Considera lo script di shell 5, che consiste in due comandi (p1 e p2) da eseguire a turno. Se lo script viene chiamato dalla riga di comando

quindi ci si aspetta che p1 scriva il suo output nel file x, e quindi anche p2 scriverà il suo output nel file x, iniziando da dove p1 si era interrotto.

Quando la shell avvia p1, il file x inizierà vuoto, quindi p1 inizierà semplicemente a scrivere nel file alla posizione 0. Tuttavia, quando p1 è terminato, è necessario un meccanismo per garantire che p2 veda la posizione iniziale non 0 (che è esattamente ciò che accade se la posizione del file è memorizzata nella tabella dei descrittori di file), ma il valore in cui pi si è fermato.

Come questo è fatto è mostrato in Fig. 10.19. Il trucco è introdurre una nuova tabella: la tabella descrittiva file aperti(apri la tabella di descrizione del file) - tra la tabella dei descrittori di file e la tabella i-node e memorizza il puntatore del file (così come il bit di lettura/scrittura) al suo interno. Nella figura, il processo genitore è la shell, e il figlio è prima il processo pi e poi il processo p2. Quando la shell crea il processo pi, la sua struttura utente (inclusa la tabella dei descrittori di file) è una copia esatta della stessa struttura della shell, quindi entrambi contengono puntatori alla stessa tabella di descrizione dei file aperti. Quando il processo pi termina, il descrittore di file della shell continua a puntare alla tabella di descrizione del file aperto, che contiene la posizione del processo p1 nel file. Quando la shell ora crea il processo p2, il nuovo processo figlio eredita automaticamente la posizione nel file, senza nuovo processo, né è necessario che la shell conosca il valore corrente di quella posizione.


Se un processo estraneo apre il file, otterrà la propria voce nella tabella di descrizione del file aperto con la sua posizione nel file, che è esattamente ciò di cui ha bisogno. Pertanto, lo scopo della tabella di descrizione del file aperto è consentire ai processi padre e figlio di condividere un singolo puntatore in un file, ma allocare puntatori personali per processi esterni.

Quindi (tornando al problema dell'esecuzione di una lettura), abbiamo mostrato come vengono determinate la posizione nel file e l'i-node. L'I-node contiene gli indirizzi del disco dei primi 12 blocchi del file. Se la posizione nel file rientra nei suoi primi 12 blocchi, allora legge blocco desiderato file e dati vengono copiati nell'utente. Per i file più lunghi di 12 blocchi, l'i-node contiene l'indirizzo del disco di un singolo blocco indiretto (Figura 10.19). Questo blocco contiene gli indirizzi del disco di ulteriori blocchi del disco. Ad esempio, se la dimensione del blocco è di 1 KB e l'indirizzo del disco è di 4 byte, un singolo blocco indiretto può memorizzare fino a 256 indirizzi del disco. Questo schema consente di supportare file di dimensioni fino a 268 KB.

Se noti un errore, seleziona una parte di testo e premi Ctrl + Invio
CONDIVIDERE: