GNU/Linux >> Linux Esercitazione >  >> Linux

Cosa succede quando un file che è stato impaginato al 100% nella cache della pagina viene modificato da un altro processo

Il rilascio continuo sostituisce quindi /apps/EXE con un nuovo eseguibile.

Questa è la parte importante.

Il modo in cui un nuovo file viene rilasciato è creando un nuovo file (ad es. /apps/EXE.tmp.20190907080000 ), scrivendo i contenuti, impostando i permessi e la proprietà e finalmente rinominalo(2) assegnandolo al nome finale /apps/EXE , sostituendo il vecchio file.

Il risultato è che il nuovo file ha un nuovo numero di inode (il che significa, in effetti, che è un file diverso.)

E il vecchio file aveva il proprio numero di inode, che in realtà è ancora in circolazione anche se il nome del file non punta più ad esso (o non ci sono più nomi di file che puntano a quell'inode).

Quindi, la chiave qui è che quando parliamo di "file" in Linux, molto spesso parliamo di "inode" poiché una volta che un file è stato aperto, l'inode è il riferimento che conserviamo al file.

Ipotesi 1 :presumo che il processo P (e chiunque altro con un descrittore di file che fa riferimento al vecchio eseguibile) continuerà a utilizzare il vecchio, in memoria /apps/EXE senza problemi, e qualsiasi nuovo processo che tenti di eseguire quel percorso otterrà il nuovo eseguibile.

Esatto.

Ipotesi 2 :presumo che se non tutte le pagine del file sono mappate in memoria, le cose andranno bene fino a quando non si verificherà un errore di pagina che richiede pagine dal file che sono state sostituite, e probabilmente si verificherà un segfault?

Errato. Il vecchio inode è ancora in circolazione, quindi gli errori di pagina del processo che utilizza il vecchio binario saranno ancora in grado di trovare quelle pagine sul disco.

Puoi vederne alcuni effetti osservando il /proc/${pid}/exe collegamento simbolico (o, equivalentemente, lsof output) per il processo che esegue il vecchio binario, che mostrerà /app/EXE (deleted) per indicare che il nome non c'è più ma l'inode è ancora presente.

Puoi anche vedere che lo spazio su disco utilizzato dal binario verrà rilasciato solo dopo che il processo è morto (supponendo che sia l'unico processo con quell'inode aperto). Controlla l'output di df prima e dopo aver terminato il processo, lo vedrai diminuire delle dimensioni di quel vecchio binario che pensavi non esistesse più.

A proposito, questo non è solo con i binari, ma con qualsiasi file aperto. Se apri un file in un processo e rimuovi il file, il file verrà mantenuto su disco fino a quando quel processo non chiude il file (o muore). Analogamente a come gli hardlink mantengono un contatore di quanti nomi puntano a un inode nel disco, il driver del filesystem (nel kernel Linux) mantiene un contatore di quanti riferimenti esistono a quell'inode in memoria e rilascerà l'inode dal disco solo dopo che tutti i riferimenti dal sistema in esecuzione saranno stati rilasciati.

Domanda 1 :Se blocchi tutte le pagine del file con qualcosa come vmtouch cambia lo scenario

Questa domanda si basa sul presupposto errato 2 che il mancato blocco delle pagine causerà segfault. Non lo farà.

Domanda 2 :Se /apps/EXE si trova su un NFS remoto, farebbe qualche differenza? (Presumo di no)

È destinato per funzionare allo stesso modo e la maggior parte delle volte funziona, ma ci sono alcuni "trucchi" con NFS.

A volte puoi vedere gli artefatti dell'eliminazione di un file che è ancora aperto in NFS (appare come un file nascosto in quella directory.)

Hai anche un modo per assegnare i numeri di dispositivo alle esportazioni NFS, per assicurarti che non vengano "rimescolati" quando il server NFS si riavvia.

Ma l'idea principale è la stessa. Il driver del client NFS utilizza ancora gli inode e cercherà di mantenere i file in giro (sul server) mentre l'inode è ancora referenziato.


Presupposto 2:presumo che se non tutte le pagine del file sono mappate in memoria, le cose andranno bene fino a quando non si verificherà un errore di pagina che richiede pagine del file che sono state sostituite, e probabilmente si verificherà un segfault?

No, non accadrà, perché il kernel non ti permetterà di aprire per scrivere e sostituire qualsiasi cosa all'interno di un file che è attualmente in esecuzione. Tale azione fallirà con ETXTBSY [1] :

cp /bin/sleep sleep; ./sleep 3600 & echo none > ./sleep
[9] 5332
bash: ./sleep: Text file busy

Quando dpkg, etc aggiorna un binario, non lo sovrascrive, ma usa rename(2) che punta semplicemente la voce della directory a un file completamente diverso e tutti i processi che hanno ancora mappature o handle aperti al vecchio file continueranno a usarlo senza problemi.

[1] il ETXBUSY la protezione non è estesa ad altri file che possono essere considerati anche "testo" (=live code / eseguibile):librerie condivise, classi java, ecc; modificare tale file mentre è mappato da un altro processo sarà causare il crash del processo. Su Linux, il linker dinamico passa diligentemente il MAP_DENYWRITE flag a mmap(2) , ma non commettere errori:non ha alcun effetto. Esempio:

$ cc -xc - <<<'void lib(){}' -shared -o lib.so
$ cc -Wl,-rpath=. lib.so -include unistd.h -xc - <<<'
   extern void lib();
   int main(){ truncate("lib.so", 0); lib(); }
'
./a.out
Bus error

la risposta di filbranden è corretta supponendo che il processo di rilascio continuo esegua una corretta sostituzione atomica dei file tramite rename . In caso contrario, ma modifica il file sul posto, le cose sono diverse. Tuttavia il tuo modello mentale è ancora sbagliato.

Non c'è possibilità che le cose vengano modificate su disco e non siano coerenti con la cache della pagina, perché la cache della pagina è la versione canonica e quello modificato. Qualsiasi scrittura su un file avviene attraverso la cache della pagina. Se è già presente, le pagine esistenti vengono modificate. Se non è ancora presente, i tentativi di modificare una pagina parziale causeranno la memorizzazione nella cache dell'intera pagina, seguita dalla modifica come se fosse già memorizzata nella cache. Le scritture che si estendono su un'intera pagina o più possono (e quasi sicuramente lo fanno) ottimizzare la fase di lettura paginandole. In ogni caso, esiste solo una versione canonica modificabile di un file(*) esistente, quella nella cache della pagina .

(*) Ho mentito leggermente. Per NFS e altri filesystem remoti, potrebbero essercene più di uno e in genere (a seconda di quale e quali opzioni di montaggio e lato server vengono utilizzate) non implementano correttamente l'atomicità e la semantica di ordinamento per le scritture. Ecco perché molti di noi li considerano fondamentalmente non funzionanti e si rifiutano di usarli per situazioni in cui ci saranno scritture in concomitanza con l'uso.


Linux
  1. Cosa succede quando eseguo il comando Cat /proc/cpuinfo?

  2. Cosa succede esattamente quando eseguo un file nella shell?

  3. Cosa succede quando viene superato il limite di larghezza di banda?

  4. Come recupero un semaforo quando il processo che lo ha decrementato a zero va in crash?

  5. Cosa succede a un handle di file aperto su Linux se il file puntato viene spostato o eliminato

SIGTERM vs SIGKILL:qual è la differenza?

Cosa sono gli inode in Linux?

Quale file in /proc viene letto dal kernel durante il processo di avvio?

Cosa succede a un processo Linux multithread se riceve un segnale?

Qual è il concetto di creare un file con zero byte in Linux?

Qual è lo sticky bit nei file system UNIX? Quando viene utilizzato?