2010-09-21 20 views
14

Qual è il modo corretto di rinominare un file in modo permanente in un file system POSIX? Specificamente chiedendo fsync sulle directory . (Se questo dipende dall'OS/FS, sto chiedendo di Linux e ext3/ext4).Come rinominare durevolmente un file in POSIX?

Nota: ci sono altre domande su StackOverflow su rinomina durevoli, ma AFAICT non affrontano Fsync-ing le directory (che è ciò che conta per me - i dati dei file che non sono nemmeno la modifica).

Al momento ho (in Python):

dstdirfd = open(dstdirpath, O_DIRECTORY|O_RDONLY) 
rename(srcdirpath + '/' + filename, dstdirpath + '/' + filename) 
fsync(dstdirfd) 

Domande specifiche:

  • Questo anche implicitamente Fsync la directory di origine? O potrei finire con il file che appare in entrambe le directory dopo un ciclo di spegnimento (nel senso che dovrei controllare il conteggio del collegamento duro e eseguire manualmente il ripristino), cioè è impossibile garantire un'operazione di spostamento atomico duratura?
  • Se io fsync la directory di origine invece di la directory di destinazione, sarà anche fsync implicitamente la directory di destinazione?
  • Esistono utili strumenti di test/debug/apprendimento (iniettori di errori, strumenti di introspezione, file system simulati, ecc.)?

Grazie in anticipo.

risposta

14

POSIX definisce che la funzione di ridenominazione deve essere atomica:

http://pubs.opengroup.org/onlinepubs/009695399/functions/rename.html

Quindi, se si rinomina (A, B), in nessun caso si dovrebbe mai vedere uno stato con il file in entrambe le directory o nessuna directory. Ci sarà sempre esattamente uno, non importa quello che fai con fsync() o se il sistema si blocca.

Ma ciò non risolve il problema di assicurarsi che l'operazione rename() sia duratura. POSIX risponde a questa domanda:

Se _POSIX_SYNCHRONIZED_IO è definita, la funzione fsync(), è costringere tutti attualmente in coda operazioni I/O associati al file indicato da fildes descrittore di file per lo stato di completamento di I/O sincronizzato. Tutte le operazioni di I/O devono essere completate come definito per il completamento dell'integrità del file I/O sincronizzato.

(da http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html)

Quindi, se si fsync() in una directory, in attesa di rinominare le operazioni devono essere trasferiti sul disco per il momento in questo ritorni. fsync() di entrambe le directory dovrebbe essere sufficiente perché l'atomicità dell'operazione rename() richiederebbe che entrambe le modifiche delle directory fossero sincronizzate in modo atomico.

Infine, in contrasto con la rivendicazione nel post citato in un'altra risposta, il razionale per questo spiega la seguente: funzione

Il fsync() destinato a forzare una scrittura fisica dei dati dal buffer cache e per assicurare che dopo un crash del sistema o un altro errore tutti i dati fino al tempo della chiamata fsync() siano registrati sul disco. Poiché i concetti di "buffer cache", "crash di sistema", "physical write" e "non volatile storage" non sono definiti qui, la formulazione deve essere più astratta.

Un sistema che ha affermato di essere conforme a POSIX e che consideravano il comportamento corretto (cioè non un bug o guasto hardware) per completare un fsync() e non persistono quei cambiamenti attraverso un crash di sistema dovrebbe essere deliberatamente travisare stesso rispetto alle specifiche.

(aggiornato con informazioni aggiuntive Re: Linux-specifici contro il comportamento portatile)

+1

Il ragionamento qui è molto sbagliato. - La "atomicità" di rename(), ad esempio, si riferisce al "newpath", sotto il quale dovrebbe essere il vecchio file (se ce n'era uno) o il file rinominato, senza nessuno stato intermedio (come visto da altri processi) . –

+0

Robert lo ha sottolineato, il nome è "atomico" rispetto all'assegnazione di un nuovo inode al nome, se il nuovo inode punta a dati non aggiornati o non è definito da POSIX. – ArekBulski

-1

La risposta alla tua domanda dipenderà molto dal sistema operativo in uso, dal tipo di file system utilizzato e dal fatto che l'origine e la destinazione siano sullo stesso dispositivo o meno.

Vorrei iniziare leggendo la pagina man di rinomina (2) sulla piattaforma che stai utilizzando.

+0

Già consultato quella pagina man - nulla di rilevante. Stai dicendo che non c'è un modo portatile per rinominare tra le directory? Sono disposto a crederlo, ma sono interessato a una dichiarazione più chiara e alle prove di supporto ideali. Inoltre, conosci la risposta dei recenti Linux di Linux con ext3/4 (dato che questa domanda è stata taggata - ha appena aggiornato anche il testo principale)? – Yang

+0

Ah ok, più semplice se è solo linux ed ext3/4 che ti interessano. Un avvertimento che la pagina man di Linux rinomina (2) cita è: 'Tuttavia, quando si sovrascrive ci sarà probabilmente una finestra in cui sia oldpath che newpath si riferiscono al file che si sta rinominando. –

-3

Mi sembra che tu stia cercando di fare il lavoro del filesystem. Se si sposta un file, il kernel e il file system sono responsabili dell'operazione atomica e del ripristino dei guasti, non del codice.

In ogni caso, questo articolo sembra rispondere alle tue domande riguardo fsync: http://blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take/

+0

Leggi prima questo post, ed è uno dei tanti che mi ha portato qui In particolare, dice: "In caso di crash del sistema poco dopo la scrittura, è più probabile che si ottiene il nuovo file rispetto al vecchio file (per la massima possibilità di questo è inoltre necessario fsync la directory in cui si trova il file)." La mia domanda riguarda cosa succede quando si rinomina tra le directory. – Yang

11

Purtroppo la risposta di Dave è sbagliata.

Non tutti i sistemi POSIX possono anche avere una memoria duratura. E se lo fanno, è ancora "permesso" di essere hosed dopo un crash del sistema. Per quei sistemi un fsync() no-op ha senso, e tale fsync() è esplicitamente permesso sotto POSIX. È anche legale che il file sia recuperabile nella vecchia directory, nella nuova directory, in entrambi o in qualsiasi altra posizione. POSIX non fornisce garanzie per arresti anomali del sistema o ripristini del file system.

La vera domanda dovrebbe essere:

come fare una ridenominazione di lunga durata sui sistemi che supportano che tramite l'API POSIX?

Hai bisogno di fare un fsync() su entrambi, fonte e directory di destinazione, perché il minimo quelli fsync) s sono tenuti a fare (è persistono come directory di origine o di destinazione dovrebbe essere simile.

Fa un fsync (destdirfd) anche implicitamente fsync alla directory di origine?

  • POSIX in generale: no, niente implica che
  • ext3/4: Non sono sicuro se sia i cambiamenti di origine e di destinazione dir finiscono nella stessa transazione nella rivista. Se lo fanno, vengono entrambi commessi insieme.

Oppure potrei finire con il file mostrando in entrambe le directory dopo un ciclo di alimentazione (“crash”), vale a dire che è impossibile garantire un'operazione di spostamento durevolmente atomica?

  • POSIX in generale: non ci sono garanzie, ma si suppone che fsync() entrambe le directory, che potrebbe non essere atomica-resistente
  • ext3/4: come fsync (molto), è minimamente necessario dipende le opzioni di montaggio. Per esempio. se montato con "dirsync" non hai bisogno di nessuno di questi due fsync() s. Al massimo hai bisogno di entrambi i fsync() s, ma sono quasi sicuro che ne è sufficiente uno (quindi resistente all'atomico).

Se si esegue il fsync della directory di origine anziché della directory di destinazione, anche questo fsync implicherà la directory di destinazione?

  • POSIX: no
  • ext3/4: Credo davvero entrambi finiscono nella stessa transazione, quindi non importa quale di essi si fsync()
  • vecchio kernel ext3: (se non sono nella stessa transazione) alcune implementazioni non così ottimali hanno fatto troppa sincronizzazione su fsync(), scommetto che ha commesso tutte le transazioni precedenti. E sì, un'implementazione normale dovrebbe prima collegarla alla destinazione e quindi rimuoverla dalla fonte. Quindi il fsync (srcdirfd) attiverà anche il fsync() della destinazione.
  • ext4/ultime ext3: se non sono nella stessa transazione, si potrebbe essere in grado di sincronizzare in modo completamente indipendente (in modo da fare entrambe le cose)

Esistono relativi strumenti di testing/debugging/apprendimento utili (iniettori di errori, strumenti di introspezione, file system simulati, ecc.)?

Per un vero incidente, no. A proposito, un vero crash va oltre il punto di vista del kernel. L'hardware potrebbe riordinare le scritture (e non riuscire a scrivere tutto), corrompendo il filesystem. Ext4 è meglio preparato contro questo, perché abilita le barriere di scrittura (opzioni di mount) per impostazione predefinita (ext3 non lo fa) e può rilevare il danneggiamento con checksum del journal (anche un'opzione di mount).

E per l'apprendimento: scopri se entrambe le modifiche sono in qualche modo collegate nel diario! :-P

+1

Questo è un punto sottile, ma non stavo dicendo che fsync() di una directory * implica * fsync() dell'altro. Era che fsync() di uno, combinato con l'atomicità di rename(), richiede che * quella specifica modifica * all'altra directory sia sincronizzata su disco.Potrei credere che non sia il caso, ma questa è la mia lettura delle specifiche. Hai un riferimento per confermare la tua interpretazione che l'atomicità non è garantita in caso di crash, anche se parte della modifica "atomica" era fsync'd? –

+0

Sì, lo faccio: il tuo link a [fsync() su opengroup.org] (http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html). "È esplicitamente inteso che è consentita un'implementazione nulla." Cioè: nessuna garanzia. - E quel collegamento desideroso di rename() e fsync() è la tua invenzione. E no, non è un punto sottile. –

+1

Concordato che i sistemi POSIX non sono necessari per rendere durevoli tali modifiche e che la vera questione è come utilizzare l'API per rendere durevole una modifica sui sistemi che la supportano. (Questo sembra pedante, però, dato che la domanda presuppone ovviamente che il sistema sottostante la supporti.) Nel chiedere un riferimento, mi riferivo alla tua affermazione che anche su sistemi che * fanno * supportano le modifiche di sincronizzazione al disco, un successo fsync() di entrambe le directory può comunque far apparire il file in entrambe le posizioni (o nessuna) dopo un arresto anomalo. –