
Vi siete mai chiesti cosa succede esattamente all’interno del kernel quando viene effettuata una classica operazione di lettura/scrittura su file? In questo articolo cercheremo di guardare sotto al “cofano” di Linux e capire meglio cosa avviene all’interno del kernel a seguito di una (apparentemente) semplice operazione di I/O.
ATTENZIONE: quello che hai appena letto è solo un estratto, l'Articolo Tecnico completo è composto da ben 1941 parole ed è riservato agli ABBONATI. Con l'Abbonamento avrai anche accesso a tutti gli altri Articoli Tecnici che potrai leggere in formato PDF per un anno. ABBONATI ORA, è semplice e sicuro.

Dal momento che siamo “in pubblico” adesso, ed è giusto che tutti possano beneficiare anche di una domanda, te la ripropongo per i nostri lettori: quanto visto in questo articolo è valido per tutte le disto linux?
Molto interessante! Complmenti! E’ un articolo semplice, ma che mi ha aperto verso un’operazione che pensavo più affidabile da parte mia. Grazie.
Domanda interessante. Vale anche per i S.O. con microkernel?
Esatto. Il discorso sulla stratificazione dell’I/O vale per tutte le distro Linux, perché il kernel è sempre lo stesso, indipendentemente dalla particolare distro scelta.
Per quanto riguarda l’esempio pratico possiamo dire che vale per tutte le distro e molto di più. Di fatto vale su tutti i sistemi POSIX-compliant (cioè che rispettano la standardizzazione delle API per sistemi UNIX), quindi anche BSD, Mac OS X, …
Per i microkernel, dipende, se il sistema in questione soddisfa gli standard POSIX allora vale, altrimenti non è detto.
molto interessante ma Linux utilizza anche una memoria su disco o virtuale chiama swap, quando entra in azione questa memoria e in che modo utilizza la chace, come interagisce con il kernel, visto che anche qui ci sono processi di I/O, e come viene dimensionata e ripulita?
Molto spesso i sistemi Linux vengono descritti come “tutto su un file” ossia, in fase iniziale tutto quello che riguarda i collegamenti con le periferiche varie viene letto e montato su un file penso sequenziale come lo gestisce questo file, non sarebbe più risparmioso caricare la periferica quando serve anche se il tempo di accesso risolta più lungo?
Lo swap entra in gioco quando il sistema si trova a corto di memoria, per fare un po’ di spazio in memoria centrale il kernel puo` decidere di liberare memoria invalidando varie cache, es. la cache dei file (page cache), oppure spostare temporaneamente memoria cosiddetta anonima (cioe` che non ha una rispettiva backing store su file – es. la memoria allocata con malloc()) su un’area di swap. In questo caso non si parla propriamente di I/O su file, trattandosi di memoria anonima e essendo completamente gestito dal kernel, cioe` lo user-space non ha modo di controllare esattamente cosa swappare. Tipicamente le pagine da swappare vengono scelte identificando un working set (cioe` memoria correntemente piu` utilizzata dal sistema) e spostando su swap alcune pagine meno utilizzate *non* appartenenti al working set. Al momento che una pagina swappata viene richiesta di nuovo dal sistema, il kernel intercetta questo evento tramite il meccanismo di page fault e provvede al caricamento della pagina dallo swap alla memoria centrale.
Non credo di capire bene la seconda domanda, ma provo a rispondere. L’astrazione “tutto e` un file” viene utilizzata solo per fornire interfacce per la comunicazione con le varie periferiche. Non e` detto che il kernel inizializzi completamente una periferica, anche se fosse presente il corrispettivo file sotto /dev. Es. quello che puo` essere fatto dal kernel in fase di inizializzazione puo` essere semplicamente un rilevamento, e nel caso in cui una particolare periferica venga rilevata si provvede a popolare la sua interfaccia tramite un file speciale (character o block device). Spesso la periferica non viene nemmeno inizializzata, es. il kernel potrebbe limitarsi a rilevarne la presenza analizzando i dati forniti dal bus e a notificare lo spazio utente della sua presenza. Poi al momento che viene utilizzata veramente (es. open() del file sotto /dev da un processo utente) il kernel potrebbe provvedere all’inizializzazione vera e propria. Ovviamente dipende tutto da com’e` stato progettato il driver, es. potrebbe inizializzare tutto al boot tramite una initcall, oppure inizializzare la periferica “on-demand” in fase di open(), o addirittuare in fase di read/write/ioctl. Spero di aver risposto alla tua domanda, altrimenti fammi sapere.
si hai risposto magnificamente a tutto, pensavo che il kernel riservasse per i driver individuati una speciale area di buffer o di stack oltre avere una certa capacita ha una certa durata di tempo o di vita, o in base alle risorse di sistema disponibili.
Sarebbe interessante sapere come vengono gestiti gli errori ed eventuali correzioni e come si evitano i stalli o criticità di sistema, e perché a volte la criticità è talmente impossibile che il sistema va in stallo(forse qualche programmatore non ritiene opportuno considerare che qualcosa va male nei trasferimenti I/O (memoria, disco, processore, ecc. o nella rigenerazione del file figlio (o pid, se non erro!))?
Grazie di avermi risposto, soprattutto per il tuo tempo.
Volevo anzitutto complimentarmi per la scorrevolezza dell’articolo che presenta in modo semplice e fruibile una materia in sé molto complessa.
Purtroppo mi resta un dubbio relativamente alla certezza di avere sempre un file congruente anche in presenza di un power fail “malizioso”. Con riferimento all’esempio relativo ad una “implementazione affidabile”, che cosa succede se il sistema di si spegne proprio durante il “rename” del file che sostituisce la copia vecchia con quella nuova? Il rename non é una operazione che la mancanza di alimentazione non possa interrompere. Come si può essere certi di non perdere sia il nuovo che il vecchio file perché la scrittura del file direttorio (in effetti i direttori sono dei file) a causa di una scrittura che si interrompe a metà (noto che la politica proposta dall’esempio non può essere adottata per proteggere l’aggiornamento del file direttorio perché presuppone un rename sicuro che invece è proprio l’oggetto di questa domanda). Questo interrogativo credo porti ad introdurre l’argomento del journaling che purtroppo conosco poco. Ma -ipotizzo- se il journaling protegge l’operazione di scrittura del file directory perché non protegge la scrittura dello stesso file dell’esempio?
Cordiali saluti.
Penso che lo conosciate gia’ un’ottimo proramma di debug I/O Sysdig