Salta al contenuto
Note per Studenti File system - interfaccia, directory e implementazione

File system - interfaccia, directory e implementazione

In questa pagina 9

Il file system è la parte del sistema operativo che dà un'interfaccia uniforme alla memoria di massa (Memoria di massa e scheduling del discoLa memoria di massa è fatta di dischi rigidi (HDD: piatti, tracce, cilindri, settori) e memorie non volatili NAND (SSD); tempo di accesso HDD = seek + latenza rotazionale (mezzo giro, 30/RPM secondi), tempo di I/O = accesso + trasferimento + overhead del controller; i blocchi sono indirizzati con un LBA lineare; per l'HDD si minimizza il seek con FCFS, SSTF (rischio di starvation), SCAN (ascensore) e C-SCAN (più uniforme), con le varianti LOOK e C-LOOK e il deadline di Linux; per le NVM contano FTL, garbage collection, overprovisioning e wear leveling; il sistema operativo formatta (fisico e logico), partiziona, gestisce il boot e lo spazio di swap; parità ed ECC rilevano e correggono errori; il RAID usa striping, mirroring e parità (livelli 0, 1, 4, 5, 6, 10) per più velocità e affidabilità, con MTTDL = 1/PDL.Memoria di massa e scheduling del disco →). Questa nota ha tre parti: l'interfaccia (che cosa vede il programmatore e l'utente), la struttura e l'implementazione (come si mappano i file sui blocchi) e il montaggio con i file system virtuali e remoti. Le system call sui file sono in System call POSIX, file descriptor e API delle socketLe system call sono le funzioni con cui un programma in user space chiede servizi al kernel (open, read, write, close, fork, pipe, dup2, socket, bind, listen, accept, connect); restituiscono -1 e impostano errno in caso di errore; un file descriptor e' un intero che indicizza la tabella dei file aperti del processo (0 stdin, 1 stdout, 2 stderr) e vale per file, pipe e socket; read e write possono trasferire MENO byte del richiesto (e sui socket TCP non c'e' nessun confine fra i messaggi), quindi servono cicli write_all e read_exact; l'API delle socket crea un punto finale di comunicazione (socket), lo lega a indirizzo e porta (bind), lo rende passivo (listen), accetta connessioni (accept) o si connette (connect); getaddrinfo traduce nomi e porte in indirizzi (IPv4 e IPv6); UDP usa sendto e recvfrom e conserva i confini dei datagrammi, TCP e' uno stream affidabile.System call POSIX, file descriptor e API delle socket →; i permessi e la sicurezza sono anche in Sicurezza e protezione nei sistemi operativiLe minacce all'accesso sono gli intrusi (masquerader, misfeasor, clandestine user) e il software malevolo (parassita: virus, logic bomb, backdoor; indipendente: worm, bot); contromisure: sistemi di rilevamento delle intrusioni (IDS, host o network, con sensori, analizzatori e interfaccia), autenticazione (identificazione + verifica con qualcosa che si sa, si ha, si è, si fa) e controllo degli accessi (permessi, sudo, SELinux, ACL, auditing, firewall); il buffer overflow scrive oltre un buffer nello stack e può sovrascrivere variabili o l'indirizzo di ritorno (code injection, shellcode); difese a compilazione (linguaggi sicuri, codice sicuro, librerie, stack protection con canarino) e a esecuzione (NX bit, ASLR, guard pages); sulla rete ci sono sniffing, spoofing e man-in-the-middle, e la crittografia (simmetrica e asimmetrica, RSA) limita mittenti e destinatari; la tolleranza ai guasti usa ridondanza (spaziale, temporale, informativa) e si misura con R(t), MTTF, MTTR e disponibilità.Sicurezza e protezione nei sistemi operativi →.

Il concetto di file

Definizione (file). Un file è uno spazio di indirizzi logici contigui, il cui contenuto è deciso da chi lo crea: dati (numerici, caratteri, binari) o programmi. Il tipo si riconosce spesso dall'estensione, che di solito non è obbligatoria: UNIX usa invece un numero magico (magic number) all'inizio del file.

Attributi

  • Nome: l'unica informazione in forma leggibile da una persona.
  • Identificatore: etichetta unica (un numero) che identifica il file nel file system.
  • Tipo, posizione (puntatore alla posizione sul dispositivo), dimensione.
  • Protezione: chi può leggere, scrivere, eseguire.
  • Data, ora e identità dell'utente: per sicurezza e controllo dell'uso.

Queste informazioni stanno nella struttura delle directory, che si trova su disco. Esistono anche attributi estesi (checksum, codifica dei caratteri).

Operazioni

Creare; scrivere (alla posizione del puntatore di scrittura); leggere (posizione del puntatore di lettura); riposizionarsi (seek); cancellare; troncare; aprire (open: cerca il file sul disco e ne porta le informazioni in memoria); chiudere (close: toglie il file dalla memoria e aggiorna le informazioni su disco).

File aperti

Per gestire i file aperti il sistema usa:

  • una tabella dei file aperti, una di sistema (condivisa) e una per processo;
  • il puntatore al file: l'ultima posizione di lettura o scrittura;
  • il contatore di aperture (file-open count): il numero di volte che il file è aperto; quando l'ultimo processo lo chiude si toglie la riga dalla tabella;
  • la posizione su disco del file, tenuta in memoria per accedere ai dati;
  • i diritti di accesso: la modalità di accesso di ogni processo.

Condivisione e lock

Alcuni sistemi offrono lock sui file. Un lock condiviso è come un lock da lettore: molti processi lo possono prendere insieme; un lock esclusivo è come quello da scrittore. Un lock obbligatorio (mandatory) nega l'accesso in base ai lock presi e richiesti; uno consultivo (advisory), usato in UNIX, lascia ai processi il compito di leggere lo stato del lock e decidere. Vedi Semafori, monitor e problemi classici di sincronizzazioneUn semaforo è un intero accessibile solo con due operazioni atomiche, wait (P: aspetta finché S > 0 e decrementa) e signal (V, in POSIX sem_post: incrementa); il semaforo contatore ha valori illimitati, quello binario vale 0 o 1; con valore iniziale 1 realizza la mutua esclusione, con valore iniziale 0 impone un ordine di esecuzione (S1 prima di S2); senza attesa attiva ogni semaforo ha una coda di processi sospesi (sleep e wakeup); i semafori si usano male con facilità (ordine sbagliato, omissioni); il monitor è un tipo di dato astratto in cui un solo processo alla volta è attivo e le variabili condizione x.wait()/x.signal() sospendono e risvegliano (in POSIX mutex più pthread_cond_t); le anomalie di liveness sono deadlock, starvation e inversione di priorità; i problemi classici sono produttore-consumatore a buffer limitato (mutex, vuote = n, piene = 0; l'ordine delle wait è importante), lettori-scrittori (rw_mutex, mutex, read_count; i lettori possono far morire di fame gli scrittori) e filosofi a cena (la soluzione ingenua con un semaforo per bacchetta va in deadlock; si evita limitando a n-1 filosofi, rompendo la simmetria o ordinando le risorse), con soluzioni in C (POSIX) e in Go (canali e sync).Semafori, monitor e problemi classici di sincronizzazione → per i lettori-scrittori.

Struttura e record

Un file può essere: una sequenza di byte o di parole (nessuna struttura); a record semplici (righe, record di lunghezza fissa o variabile); a struttura complessa (documento formattato, file eseguibile rilocabile). Il record logico (la minima unità di dati) raramente coincide con il record fisico (il settore): UNIX indirizza i singoli byte, ma il disco ha settori da 512 o 4096 byte, quindi c'è frammentazione interna nell'ultimo blocco.

Metodi di accesso

  • Sequenziale: read next, write next, reset; come un nastro.
  • Diretto: read n, write n, position to n, con nn numero di blocco relativo all'inizio del file (il sistema decide dove metterlo); può simulare l'accesso sequenziale.
  • Altri (per esempio a indice): si costruisce un indice del file, tenuto in memoria; se è troppo grande, si fa un indice dell'indice.

Directory

Definizione (directory). Una directory è un file speciale che contiene una raccolta di voci con le informazioni sui file. Le directory e i file risiedono su disco.

Operazioni: cercare, creare, cancellare un file; elencare una directory; rinominare; percorrere il file system (la directory corrente e le sue sottodirectory). Una buona organizzazione dà efficienza (trovare presto un file), nomi comodi (due utenti possono avere lo stesso nome per file diversi; lo stesso file può avere più nomi) e raggruppamento (per esempio per proprietà).

organizzazione caratteristica pregi difetti
livello singolo una directory per tutti semplice problemi di nomi e di raggruppamento
due livelli una directory per utente; percorso = utente + file stesso nome per utenti diversi; ricerca efficiente nessun raggruppamento
ad albero sottodirectory; un bit per voce dice se è file (0) o directory (1); ogni processo ha una directory corrente raggruppamento, percorsi assoluti e relativi niente condivisione tra rami
a grafo aciclico file e sottodirectory condivisi tramite link un elemento con più nomi (aliasing) cancellazioni e puntatori pendenti
a grafo generale sono possibili cicli massima libertà cicli e ricerche infinite

In UNIX e Linux il percorso assoluto inizia dalla radice /, quello relativo parte dalla directory corrente (.; .. è il genitore).

Nel grafo aciclico un file ha più nomi. Se si cancella /dict/w/list, il nome /spell/words diventa un puntatore pendente (dangling). Soluzioni: puntatori inversi per eliminare tutti i riferimenti; eliminare gli altri riferimenti solo quando si usano; conservare il file finché non sono cancellati tutti i riferimenti (è la scelta di UNIX con il contatore dei link).

Definizione (hard link e link simbolico). Un hard link è un altro nome (una voce di directory) per lo stesso inode: ha la stessa identità del file, non si distingue dall'originale. Un link simbolico (symbolic link) è un file speciale che contiene il percorso di un altro file: un puntatore a un puntatore. In Linux: ln nome_file nome_link crea un hard link, ln -s nome_file nome_simbolico un link simbolico.

hard link link simbolico
inode lo stesso del file uno proprio
contatore dei link del file aumenta di 1 non cambia
se si cancella l'originale il file esiste ancora (finché c'è un link) resta pendente
tra file system diversi no sì
directory di norma no sì

Nel grafo generale i cicli si gestiscono in quattro modi: vietando i link a directory; usando un algoritmo di rilevamento di cicli a ogni nuovo link; permettendoli ma evitando le ricerche infinite; con la garbage collection (controllo periodico dei blocchi irraggiungibili). I cicli dei grafi orientati sono trattati in Grafi diretti e ordinamento topologicoGrafi diretti (archi orientati, grado entrante e uscente, cammini e cicli diretti), visite su grafi diretti e tipi di archi; DAG; ordinamento topologico con l'algoritmo basato sui gradi entranti e con la DFS (reverse postorder), correttezza e costo Theta(n+m); esempio svolto.Grafi diretti e ordinamento topologico →. Un esercizio sui link, con la dimensione e i blocchi di un link, è Esercizio - Hard link e link simbolici, fast symlink (laboratorio 10).

Protezione e permessi

Il proprietario di un file deve poter controllare cosa si può fare e da chi. Tipi di accesso: lettura, scrittura, esecuzione, aggiunta in fondo, cancellazione, elenco.

In UNIX e Linux le modalità sono read, write, execute (rwx) e le classi di utenti sono tre: proprietario (owner), gruppo (group), altri (public). Ognuna è un numero ottale di 3 bit (r=4, w=2, x=1).

Esempio. chmod 754 abc: proprietario 7=111=rwx7=111=\text{rwx}, gruppo 5=101=r-x5=101=\text{r-x}, altri 4=100=r–4=100=\text{r--}, quindi rwxr-xr--. Con chmod 444 abcde.txt il file è di sola lettura per tutti, anche per il proprietario. Un gruppo si crea con sudo groupadd team, si assegna con sudo chgrp team abc.

Windows usa liste di controllo degli accessi (ACL) per utente e gruppo; in Linux man acl. Il programma C del laboratorio 9, con stat() e chmod(), è in Esercizio - Permessi dei file con stat e chmod (laboratorio 9).

Struttura del file system

Un disco permette riscrittura e accesso casuale; i trasferimenti sono per blocchi di settori (di solito 512 o 4096 byte). Il file system fa corrispondere la visione logica del file ai blocchi fisici.

Strati

  1. File system logico (logical file system): gestisce i metadati; traduce il nome del file in un numero, un handle e una posizione mantenendo i blocchi di controllo del file (FCB; in UNIX inode); gestisce la struttura delle directory e la protezione.
  2. Modulo di organizzazione dei file: traduce il numero di blocco logico in fisico; gestisce lo spazio libero e l'allocazione.
  3. File system di base: comandi generici ("leggi il blocco 12"); gestisce buffer e cache in memoria.
  4. Controllo dell'I/O: driver e gestori delle interruzioni per i dispositivi: traduce comandi come "leggi dal disco 1, cilindro 72, traccia 2, settore 10" in operazioni sul controller (vedi Sistemi di I-O e memory-mapped I-OIl sistema operativo nasconde la varietà dei dispositivi con driver e un'interfaccia uniforme (dispositivi a blocchi, a caratteri, di rete, timer, ioctl); l'hardware è fatto di porte, bus e controller con registri di dato, stato e controllo, indirizzati con istruzioni di I/O dedicate o con il memory-mapped I/O; la CPU comunica con il dispositivo con il polling (busy wait, adatto a dispositivi veloci), con le interruzioni (linea IRQ, vettore, priorità, mascherabili) o con il DMA (trasferimenti di blocchi senza CPU, un'interruzione alla fine); le chiamate possono essere bloccanti, non bloccanti o asincrone; le istruzioni di I/O sono privilegiate e si passa dalle system call; il kernel gestisce errori, buffer e protezione; mmap() mappa un file nello spazio di indirizzi di un processo: accesso con load e store, caricamento pigro con il demand paging, meno chiamate di sistema e meno copie, condivisione con MAP_SHARED.Sistemi di I-O e memory-mapped I-O →).

Esistono molti file system, anche nello stesso sistema operativo: ISO 9660 (CD-ROM), UFS e FFS (UNIX), FAT, FAT32 e NTFS (Windows), ext3 e ext4 (Linux, che ne ha più di 100 tipi), e ZFS, GoogleFS, FUSE e altri.

Strutture su disco

  • Blocco di controllo di avvio (boot control block): le informazioni per avviare il sistema da quel volume (di solito il primo blocco); in UFS si chiama boot block, in NTFS partition boot sector.
  • Blocco di controllo del volume (volume control block): numero di blocchi, blocchi liberi, dimensione del blocco, puntatori ai blocchi liberi; in UFS è il superblock, in NTFS la master file table.
  • Struttura delle directory e FCB dei file. L'FCB contiene permessi, proprietario, date, dimensione e puntatori ai blocchi (non il nome del file, che sta nella directory).

Strutture in memoria

Tabella dei montaggi (mount table); cache delle directory recenti; tabella dei file aperti di sistema (copia dell'FCB di ogni file aperto); tabella dei file aperti del processo (puntatori alla tabella di sistema); buffer per le letture e scritture. Con open si cerca il file nelle directory, si carica l'FCB nella tabella di sistema e si restituisce un descrittore (indice della tabella del processo); con read i dati arrivano al buffer e sono copiati nell'indirizzo del processo.

Implementazione delle directory

Metodi di allocazione

L'allocazione stabilisce come si assegnano i blocchi del disco ai file. Tre metodi.

Allocazione contigua

Ogni file occupa un insieme di blocchi contigui. Serve solo l'indirizzo iniziale e la lunghezza. Migliori prestazioni (sequenziale e diretto). Problemi: trovare spazio, conoscere la dimensione in anticipo (spesso impossibile), frammentazione esterna (serve una compattazione, in linea o no). Una versione migliore, a extent (blocchi contigui di spazio): un file è formato da uno o più extent, e se uno non basta se ne aggiunge un altro collegato; può ancora soffrire di frammentazione interna ed esterna. L'usa ext4.

Allocazione concatenata

Ogni file è una lista concatenata di blocchi, sparsi sul disco; ogni blocco contiene il puntatore al successivo. La directory punta al primo blocco (e all'ultimo o al numero di blocchi). Se il blocco è 512 byte e l'indirizzo 4 byte, restano 508 byte utili. Il file finisce con un puntatore nullo.

Pro: nessuna frammentazione esterna. Contro: per trovare un blocco servono molti I/O e seek, quindi è inadatta all'accesso diretto; i puntatori consumano spazio (si può ridurre raggruppando blocchi contigui in cluster, a costo di più frammentazione interna); affidabilità: se si rovina un blocco o c'è un errore software, il file è corrotto.

FAT (file allocation table): variante della concatenata usata da MS-DOS e altri. Una tabella all'inizio del volume ha una riga per ogni blocco; la riga contiene l'indice del blocco successivo del file; la directory punta al primo blocco. L'accesso casuale si fa cercando nella tabella (più veloce che girare per il disco), e va meglio se la tabella è in cache in memoria. FAT-XX indica il numero di bit per l'indice di blocco: con XX bit si hanno 2X2^X blocchi.

Allocazione indicizzata

Un solo blocco indice contiene tutti i puntatori del file; la directory punta al blocco indice e l'ii-esimo elemento punta all'ii-esimo blocco dati. Se il file è piccolo il blocco indice è sprecato. Soluzioni: schema concatenato (un puntatore a un altro blocco indice), indice a più livelli (il primo livello punta ai secondi) oppure schema combinato.

Definizione (schema combinato, inode UNIX). L'inode contiene 15 puntatori: i primi 12 diretti ai blocchi dati, il 13° punta a un blocco indiretto singolo (puntatori a blocchi dati), il 14° a un blocco indiretto doppio (puntatori a blocchi di puntatori), il 15° a un blocco indiretto triplo.

Con blocchi da 512 byte e indirizzi da 4 byte, un blocco contiene 512/4=128512/4=128 puntatori; un indiretto doppio indirizza 128⋅128⋅512=8 MB128\cdot128\cdot512=8\ \text{MB}. In generale, con blocco da BB byte e puntatori da pp byte: n=B/pn=B/p puntatori per blocco e la dimensione massima di un file è (12+n+n2+n3) B(12+n+n^2+n^3)\,B (se i puntatori diretti sono 12). Con blocchi da 4 KB e puntatori da 4 byte, n=1024n=1024 e il massimo è circa 4 TB. Calcoli completi in Esercizio - Inode e dimensione massima dei file (eserciziario, esercizi 63, 97, 105 e 111).

ext4 e gli extent. ext4 sostituisce lo schema combinato (troppo complesso per file grandi) con un sistema a extent: un intervallo di blocchi fisici contigui che può mappare fino a 128 MiB. L'inode ne referenzia direttamente 4 (fino a 512 MiB direttamente accessibili); se un file ha più di 4 extent, gli altri sono indicizzati in un albero. ext4 supporta in teoria volumi fino a 64 ZiB e file fino a 16 TiB con blocchi da 4 KiB.

Prestazioni dei metodi

La scelta dipende dal tipo di accesso: la contigua è ottima per accesso sequenziale e diretto; la concatenata è buona per il sequenziale, non per il diretto; la indicizzata è più complessa (un accesso a un blocco può richiedere 2 letture dell'indice, poi la lettura del dato). Si può dichiarare il tipo di accesso alla creazione, scegliendo contigua o concatenata. Per le NVM, senza testine, servono ottimizzazioni diverse: i vecchi algoritmi sprecano CPU per evitare un movimento della testina che non c'è. Un esercizio di confronto è Esercizio - Allocazione dei file con metodo contiguo, concatenato, indicizzato e FAT (eserciziario, esercizi 42, 53, 65, 71, 104, 108, 113 e 119).

Gestione dello spazio libero

Il file system tiene una lista dello spazio libero (non necessariamente una lista vera).

  • Vettore di bit (bitmap): nn bit per nn blocchi, con 1 per libero e 0 per occupato (o il contrario). Esempio: blocchi liberi 0, 5, 6, 9 →\to 10000110010…. La ricerca è rapida perché le CPU hanno istruzioni che restituiscono la posizione del primo bit a 1 di una parola. Efficiente se sta in memoria, un problema per dischi grandi: blocco da 4 KB =212=2^{12} byte, disco da 1 TB =240=2^{40} byte, n=240/212=228n=2^{40}/2^{12}=2^{28} bit, cioè 32 MB (con cluster da 4 blocchi, 8 MB).
  • Lista concatenata dei blocchi liberi: ogni blocco libero contiene il puntatore al successivo; basta ricordare la testa; nessuno spazio sprecato; non è facile avere spazio contiguo.
  • Raggruppamento (grouping): il primo blocco libero contiene gli indirizzi di altri n−1n-1 blocchi liberi e un puntatore al blocco successivo di questo tipo.
  • Conteggio (counting): si conserva l'indirizzo del primo blocco libero e il numero di blocchi liberi che seguono; più efficiente se il conteggio medio è maggiore di 1 (tipico con extent e allocazione contigua).

Esercizi: Esercizio - Spazio libero con bitmap e lista concatenata (eserciziario, esercizi 41, 98 e 120).

Montaggio e file system virtuali

Un calcolatore può avere più dispositivi di memoria; si dividono in partizioni, i volumi possono occupare più partizioni, e ogni volume di solito contiene un solo file system. La partizione radice contiene il sistema operativo e si monta all'avvio. Le altre si montano su un punto di montaggio (mount point), una directory dell'albero esistente: per esempio una partizione montata in /users. Al montaggio si controlla la coerenza del file system: se i metadati sono corretti, si aggiunge alla tabella dei montaggi e si permette l'accesso.

Con file system condivisi i permessi devono valere anche tra sistemi diversi: che succede se la partizione montata ha file di utenti che non esistono nel sistema ospite? Il comportamento dipende dal sistema operativo e dal file system (per esempio si assegnano a un amministratore).

VFS (virtual file system)

Il VFS di UNIX e Linux è un modo orientato agli oggetti di realizzare i file system: la stessa interfaccia di system call serve per file system di tipo diverso (o di rete). Separa le operazioni generiche dall'implementazione; il VFS invia l'operazione alla routine del file system giusto.

Linux ha quattro tipi di oggetto: file (file aperto), dentry (voce di directory), inode (singolo file) e superblock (intero file system). Ogni oggetto ha un puntatore a una tabella di funzioni con gli indirizzi delle routine che il singolo file system deve implementare: per il file, open, close, read, write, mmap. Questo è l'equivalente in C dell'ereditarietà con funzioni virtuali. Il comando findmnt -lo TARGET,FSTYPE elenca i file system montati (nell'esempio del corso: sysfs, proc, tmpfs, devpts, nfs per la home e ext4 per la radice).

File system distribuiti e NFS

Condivisione di file in rete: a mano (per esempio FTP), con il Web (browser, accesso anche anonimo) o con un file system distribuito (DFS), in cui le directory remote sono visibili dalla macchina locale. In un modello client-server il server offre l'accesso tramite un protocollo; di solito gli utenti di client e server devono coincidere, si monta il file system remoto, le operazioni sono inviate al server per conto dell'utente, il server controlla i permessi e restituisce un handle usato fino alla chiusura.

La semantica di consistenza dice quando le modifiche saranno viste dagli altri utenti e come sincronizzare le operazioni in rete. In UFS i dati scritti in un file aperto sono subito visibili agli altri, e gli utenti possono condividere il puntatore alla posizione corrente. In AFS (Andrew file system) i dati scritti non si vedono durante la sessione: ci sono più copie, modificate separatamente, e alla fine ne resta una sola.

NFS (Sun Network File System) è un'implementazione e una specifica per accedere a file remoti in LAN o WAN (anche su protocolli non affidabili come UDP). Una directory remota si monta su una directory locale e appare come un sottoalbero locale (anche in cascata: per esempio montare S1:/usr/shared su U:/usr/local); l'indipendenza dalla macchina viene da RPC (Remote Procedure Call) sopra XDR (External Data Representation). L'architettura ha tre strati: interfaccia UNIX (open, read, write, close), strato VFS (distingue file locali e remoti, e i locali per tipo di file system), strato del servizio NFS (realizza il protocollo).

Blocchi, frammentazione e stat (laboratori 9 e 10)

Il comando stat nomefile e la funzione C stat() (o lstat(), che riconosce anche i link simbolici) restituiscono una struct stat con st_ino (numero di inode), st_mode (tipo e permessi), st_nlink (numero di hard link), st_uid, st_gid, st_size (byte) e st_blocks (numero di blocchi da 512 byte allocati); statvfs() dà informazioni sul file system montato, come f_bsize (dimensione del blocco, di solito 4096), f_blocks, f_bfree, f_files.

Per ragioni storiche i blocchi contati da stat sono da 512 byte, mentre il blocco fisico di I/O è da 4096. Un file di 1948 byte occupa 1 blocco fisico da 4096, cioè 8⋅5128\cdot512: Blocks: 8. Un file di 17 112 byte ne occupa 5 (⌈17112/4096⌉=5\lceil17112/4096\rceil=5): Blocks: 40, e la frammentazione interna è 5⋅4096−17112=33685\cdot4096-17112=3368 byte. Un file di 1 byte occupa comunque 4096 byte. Nel laboratorio 10, il file di 1 981 975 byte richiede ⌈1981975/4096⌉=484\lceil1981975/4096\rceil=484 blocchi e la frammentazione interna è 484⋅4096−1981975=489484\cdot4096-1981975=489 byte. Il programma completo è in Esercizio - Frammentazione interna di un file con stat e statvfs (laboratorio 10).

In ext4, se il nome del file puntato è lungo meno di 60 caratteri, il link simbolico è contenuto nell'inode stesso (che è già in memoria): è un fast symlink, e non occupa nessun blocco dati. Oltre i 60 caratteri serve un blocco.

Domande d'esame

  1. Confrontare allocazione contigua, concatenata e indicizzata. Contigua: base e lunghezza, ottimo accesso sequenziale e diretto, frammentazione esterna e dimensione da conoscere. Concatenata: nessuna frammentazione esterna, accesso diretto lento, puntatori in ogni blocco, poco affidabile (FAT la migliora con la tabella in cache). Indicizzata: accesso diretto con un blocco indice, ma il blocco indice è sprecato per file piccoli (schema combinato dell'inode).
  2. Dimensione massima di un file con inode da 12 puntatori diretti, uno indiretto e uno doppio, blocchi da 1 KB e puntatori da 4 byte. n=256n=256: (12+256+2562) KB=65 804(12+256+256^2)\,\text{KB}=65\,804 KB.
  3. Differenza tra hard link e link simbolico; cosa succede cancellando il file originale. L'hard link è un altro nome dello stesso inode (contatore dei link); il file esiste finché c'è un nome. Il link simbolico contiene un percorso: dopo la cancellazione resta pendente. Non si possono fare hard link tra file system diversi.

Versione ripasso

File. Spazio di indirizzi logici contigui; tipo dall'estensione (UNIX: numero magico). Attributi: nome (l'unico leggibile), identificatore, tipo, posizione, dimensione, protezione, date e utente. Operazioni: create, write, read, seek, delete, truncate, open (cerca il file e ne porta le informazioni in memoria), close (le aggiorna su disco). File aperti: tabella di sistema e per processo, puntatore al file, contatore di aperture, posizione su disco, diritti. Lock: condiviso (come un lettore) o esclusivo (scrittore); obbligatorio o consultivo (UNIX) (Semafori, monitor e problemi classici di sincronizzazioneUn semaforo è un intero accessibile solo con due operazioni atomiche, wait (P: aspetta finché S > 0 e decrementa) e signal (V, in POSIX sem_post: incrementa); il semaforo contatore ha valori illimitati, quello binario vale 0 o 1; con valore iniziale 1 realizza la mutua esclusione, con valore iniziale 0 impone un ordine di esecuzione (S1 prima di S2); senza attesa attiva ogni semaforo ha una coda di processi sospesi (sleep e wakeup); i semafori si usano male con facilità (ordine sbagliato, omissioni); il monitor è un tipo di dato astratto in cui un solo processo alla volta è attivo e le variabili condizione x.wait()/x.signal() sospendono e risvegliano (in POSIX mutex più pthread_cond_t); le anomalie di liveness sono deadlock, starvation e inversione di priorità; i problemi classici sono produttore-consumatore a buffer limitato (mutex, vuote = n, piene = 0; l'ordine delle wait è importante), lettori-scrittori (rw_mutex, mutex, read_count; i lettori possono far morire di fame gli scrittori) e filosofi a cena (la soluzione ingenua con un semaforo per bacchetta va in deadlock; si evita limitando a n-1 filosofi, rompendo la simmetria o ordinando le risorse), con soluzioni in C (POSIX) e in Go (canali e sync).Semafori, monitor e problemi classici di sincronizzazione →). Struttura: byte, record, strutture complesse. Record logico ≠\ne settore →\to frammentazione interna. Accesso: sequenziale (read next, reset), diretto (read n, blocco relativo), a indice (anche indice dell'indice).

Directory. File speciale con le voci dei file. Operazioni: cerca, crea, cancella, elenca, rinomina, percorri. Organizzazioni: livello singolo (problemi di nomi e raggruppamento), due livelli (percorso == utente ++ file), ad albero (bit file/directory, directory corrente, percorsi assoluti / e relativi .), grafo aciclico (link, aliasing, puntatori pendenti), grafo generale (cicli: vietarli, rilevarli, garbage collection). Cancellazione con link: conservare il file finché c'è un riferimento. Hard link == altro nome per lo stesso inode (contatore dei link, ln); link simbolico == file speciale con un percorso (ln -s, può restare pendente, vale tra file system diversi, anche per directory). Nel grafo generale i cicli (Grafi diretti e ordinamento topologicoGrafi diretti (archi orientati, grado entrante e uscente, cammini e cicli diretti), visite su grafi diretti e tipi di archi; DAG; ordinamento topologico con l'algoritmo basato sui gradi entranti e con la DFS (reverse postorder), correttezza e costo Theta(n+m); esempio svolto.Grafi diretti e ordinamento topologico →).

Permessi. r, w, x per proprietario, gruppo, altri; r=4, w=2, x=1; chmod 754 →\to rwxr-xr--; chmod 444 →\to sola lettura per tutti; chgrp, groupadd; ACL (man acl) in Windows e Linux (Sicurezza e protezione nei sistemi operativiLe minacce all'accesso sono gli intrusi (masquerader, misfeasor, clandestine user) e il software malevolo (parassita: virus, logic bomb, backdoor; indipendente: worm, bot); contromisure: sistemi di rilevamento delle intrusioni (IDS, host o network, con sensori, analizzatori e interfaccia), autenticazione (identificazione + verifica con qualcosa che si sa, si ha, si è, si fa) e controllo degli accessi (permessi, sudo, SELinux, ACL, auditing, firewall); il buffer overflow scrive oltre un buffer nello stack e può sovrascrivere variabili o l'indirizzo di ritorno (code injection, shellcode); difese a compilazione (linguaggi sicuri, codice sicuro, librerie, stack protection con canarino) e a esecuzione (NX bit, ASLR, guard pages); sulla rete ci sono sniffing, spoofing e man-in-the-middle, e la crittografia (simmetrica e asimmetrica, RSA) limita mittenti e destinatari; la tolleranza ai guasti usa ridondanza (spaziale, temporale, informativa) e si misura con R(t), MTTF, MTTR e disponibilità.Sicurezza e protezione nei sistemi operativi →).

Strati. (1) file system logico: metadati, nome →\to numero/handle, FCB (inode UNIX), directory, protezione; (2) organizzazione dei file: blocco logico →\to fisico, spazio libero, allocazione; (3) file system di base: comandi generici, buffer e cache; (4) controllo dell'I/O: driver e interruzioni (Sistemi di I-O e memory-mapped I-OIl sistema operativo nasconde la varietà dei dispositivi con driver e un'interfaccia uniforme (dispositivi a blocchi, a caratteri, di rete, timer, ioctl); l'hardware è fatto di porte, bus e controller con registri di dato, stato e controllo, indirizzati con istruzioni di I/O dedicate o con il memory-mapped I/O; la CPU comunica con il dispositivo con il polling (busy wait, adatto a dispositivi veloci), con le interruzioni (linea IRQ, vettore, priorità, mascherabili) o con il DMA (trasferimenti di blocchi senza CPU, un'interruzione alla fine); le chiamate possono essere bloccanti, non bloccanti o asincrone; le istruzioni di I/O sono privilegiate e si passa dalle system call; il kernel gestisce errori, buffer e protezione; mmap() mappa un file nello spazio di indirizzi di un processo: accesso con load e store, caricamento pigro con il demand paging, meno chiamate di sistema e meno copie, condivisione con MAP_SHARED.Sistemi di I-O e memory-mapped I-O →). Tipi: ISO 9660, UFS, FFS, FAT, NTFS, ext3/ext4 (Linux ne ha più di 100), ZFS, FUSE. Su disco: boot block (UFS) o partition boot sector (NTFS); volume control block (superblock, master file table); directory; FCB (permessi, proprietario, date, dimensione, puntatori; non il nome). In memoria: mount table, cache delle directory, tabella dei file aperti di sistema (copia dell'FCB) e per processo, buffer. Directory: lista lineare (ricerca lenta) o tabella hash (Tabelle hashTabella hash per implementare una mappa: funzione hash = hash code + compression function, bucket array, separate chaining; hash code per numeri e stringhe (polynomial, cyclic shift), division e MAD; load factor, complessità al caso pessimo Theta(n) e medio O(1+lambda), rehashing; esempio svolto con inserimenti e collisioni.Tabelle hash →).

Allocazione.

  • Contigua: base ++ lunghezza, ottima per sequenziale e diretto; frammentazione esterna, dimensione da conoscere; versione a extent (ext4).
  • Concatenata: lista di blocchi con puntatore (512 B con indirizzo da 4 B →\to 508 utili); nessuna frammentazione esterna; accesso diretto lento; poco affidabile. FAT: tabella con una riga per blocco, indice del successivo; in cache in memoria; FAT-XX =2X=2^X blocchi.
  • Indicizzata: blocco indice; se piccolo il file lo spreca; schema concatenato, a più livelli o combinato: inode con 15 puntatori (12 diretti, singolo, doppio, triplo). n=B/pn=B/p; massimo (12+n+n2+n3)B(12+n+n^2+n^3)B; B=512B=512, p=4p=4: 128⋅128⋅512=8128\cdot128\cdot512=8 MB per il doppio; B=4B=4 KB: circa 4 TB. ext4: extent fino a 128 MiB, 4 nell'inode (512 MiB), poi albero; volumi fino a 64 ZiB, file fino a 16 TiB.

Prestazioni: contigua per sequenziale e diretto, concatenata per sequenziale, indicizzata più complessa (2 letture dell'indice ++ dato); NVM: ottimizzazioni diverse.

Spazio libero. Bitmap (240/212=2282^{40}/2^{12}=2^{28} bit =32=32 MB per 1 TB e blocchi da 4 KB, 8 MB con cluster da 4; istruzioni per il primo bit a 1), lista concatenata (nessuno spreco, non facile avere spazio contiguo), raggruppamento (il primo libero contiene n−1n-1 indirizzi), conteggio (primo blocco ++ quanti seguono).

Mount e VFS. Partizioni, volumi; radice montata all'avvio; altre su un mount point, controllo di coerenza; permessi tra sistemi diversi. VFS (Linux: oggetti file, dentry, inode, superblock con tabelle di funzioni open, close, read, write, mmap); findmnt -lo TARGET,FSTYPE. DFS: FTP, Web, file system distribuito; semantica UFS (scritture subito visibili) contro AFS (non visibili durante la sessione, resta l'ultima copia); NFS con RPC e XDR, tre strati (interfaccia UNIX, VFS, servizio NFS), montaggio anche in cascata.

stat e laboratori. st_blocks conta blocchi da 512 byte, il blocco fisico è 4096 (88 blocchi contati): 1948 byte →\to Blocks: 8; 17 112 byte →\to 5 blocchi fisici =40=40, frammentazione 5⋅4096−17112=33685\cdot4096-17112=3368; 1 981 975 byte →484\to484 blocchi, 484⋅4096−1981975=489484\cdot4096-1981975=489. Fast symlink (ext4): percorso <60<60 caratteri nell'inode, nessun blocco (Esercizio - Hard link e link simbolici, fast symlink (laboratorio 10)).

Domande tipiche. Contigua contro concatenata contro indicizzata; massimo file con 12 diretti + singolo + doppio (B=1B=1 KB, p=4p=4 B →65 804\to65\,804 KB); hard contro simbolico; bitmap per un disco dato.

Errori tipici. Nome nell'FCB; blocchi di stat da 4096; blocchi indice non contati; frammentazione B−dim mod BB-\text{dim}\bmod B per file multipli del blocco; hard link e simbolici scambiati.

Collegamenti: Memoria di massa e scheduling del discoLa memoria di massa è fatta di dischi rigidi (HDD: piatti, tracce, cilindri, settori) e memorie non volatili NAND (SSD); tempo di accesso HDD = seek + latenza rotazionale (mezzo giro, 30/RPM secondi), tempo di I/O = accesso + trasferimento + overhead del controller; i blocchi sono indirizzati con un LBA lineare; per l'HDD si minimizza il seek con FCFS, SSTF (rischio di starvation), SCAN (ascensore) e C-SCAN (più uniforme), con le varianti LOOK e C-LOOK e il deadline di Linux; per le NVM contano FTL, garbage collection, overprovisioning e wear leveling; il sistema operativo formatta (fisico e logico), partiziona, gestisce il boot e lo spazio di swap; parità ed ECC rilevano e correggono errori; il RAID usa striping, mirroring e parità (livelli 0, 1, 4, 5, 6, 10) per più velocità e affidabilità, con MTTDL = 1/PDL.Memoria di massa e scheduling del disco →, Sistemi di I-O e memory-mapped I-OIl sistema operativo nasconde la varietà dei dispositivi con driver e un'interfaccia uniforme (dispositivi a blocchi, a caratteri, di rete, timer, ioctl); l'hardware è fatto di porte, bus e controller con registri di dato, stato e controllo, indirizzati con istruzioni di I/O dedicate o con il memory-mapped I/O; la CPU comunica con il dispositivo con il polling (busy wait, adatto a dispositivi veloci), con le interruzioni (linea IRQ, vettore, priorità, mascherabili) o con il DMA (trasferimenti di blocchi senza CPU, un'interruzione alla fine); le chiamate possono essere bloccanti, non bloccanti o asincrone; le istruzioni di I/O sono privilegiate e si passa dalle system call; il kernel gestisce errori, buffer e protezione; mmap() mappa un file nello spazio di indirizzi di un processo: accesso con load e store, caricamento pigro con il demand paging, meno chiamate di sistema e meno copie, condivisione con MAP_SHARED.Sistemi di I-O e memory-mapped I-O →, Sicurezza e protezione nei sistemi operativiLe minacce all'accesso sono gli intrusi (masquerader, misfeasor, clandestine user) e il software malevolo (parassita: virus, logic bomb, backdoor; indipendente: worm, bot); contromisure: sistemi di rilevamento delle intrusioni (IDS, host o network, con sensori, analizzatori e interfaccia), autenticazione (identificazione + verifica con qualcosa che si sa, si ha, si è, si fa) e controllo degli accessi (permessi, sudo, SELinux, ACL, auditing, firewall); il buffer overflow scrive oltre un buffer nello stack e può sovrascrivere variabili o l'indirizzo di ritorno (code injection, shellcode); difese a compilazione (linguaggi sicuri, codice sicuro, librerie, stack protection con canarino) e a esecuzione (NX bit, ASLR, guard pages); sulla rete ci sono sniffing, spoofing e man-in-the-middle, e la crittografia (simmetrica e asimmetrica, RSA) limita mittenti e destinatari; la tolleranza ai guasti usa ridondanza (spaziale, temporale, informativa) e si misura con R(t), MTTF, MTTR e disponibilità.Sicurezza e protezione nei sistemi operativi →, System call POSIX, file descriptor e API delle socketLe system call sono le funzioni con cui un programma in user space chiede servizi al kernel (open, read, write, close, fork, pipe, dup2, socket, bind, listen, accept, connect); restituiscono -1 e impostano errno in caso di errore; un file descriptor e' un intero che indicizza la tabella dei file aperti del processo (0 stdin, 1 stdout, 2 stderr) e vale per file, pipe e socket; read e write possono trasferire MENO byte del richiesto (e sui socket TCP non c'e' nessun confine fra i messaggi), quindi servono cicli write_all e read_exact; l'API delle socket crea un punto finale di comunicazione (socket), lo lega a indirizzo e porta (bind), lo rende passivo (listen), accetta connessioni (accept) o si connette (connect); getaddrinfo traduce nomi e porte in indirizzi (IPv4 e IPv6); UDP usa sendto e recvfrom e conserva i confini dei datagrammi, TCP e' uno stream affidabile.System call POSIX, file descriptor e API delle socket →.

Esercizi su questo argomento

Teoria collegata