From: Simone Piccardi Date: Tue, 27 Nov 2001 00:20:20 +0000 (+0000) Subject: Messe fsync, sync. X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=4200529d613212e34c8cd8afd1628aedc20d74f2 Messe fsync, sync. --- diff --git a/filestd.tex b/filestd.tex index 0ea9995..e5ea8fd 100644 --- a/filestd.tex +++ b/filestd.tex @@ -126,19 +126,19 @@ riguarda l'aspetto della scrittura dei dati sul file. I caratteri che vengono scritti su uno stream normalmente vengono accumulati in un buffer e poi trasmessi in blocco in maniera asincrona rispetto alla -scrittura (quello che viene chiamato il \textit{flush} dei dati) tutte le -volte che il buffer viene riempito. Un comportamento analogo avviene anche in -lettura (cioè dal file viene letto un blocco di dati, anche se se ne sono -richiesti una quantità inferiore), ma la cosa ovviamente ha rilevanza -inferiore, dato che i dati letti sono sempre gli stessi; in caso di scrittura -invece, quando si ha un accesso contemporaneo allo stesso file (ad esempio da -parte di un altro processo) si potranno vedere solo le parti effettivamente -scritte, e non quelle ancora presenti nel buffer. +scrittura (quello che viene chiamato lo \textsl{scarico}, dall'ingelese +\textit{flush}, dei dati) tutte le volte che il buffer viene riempito. Un +comportamento analogo avviene anche in lettura (cioè dal file viene letto un +blocco di dati, anche se se ne sono richiesti una quantità inferiore), ma la +cosa ovviamente ha rilevanza inferiore, dato che i dati letti sono sempre gli +stessi; in caso di scrittura invece, quando si ha un accesso contemporaneo +allo stesso file (ad esempio da parte di un altro processo) si potranno vedere +solo le parti effettivamente scritte, e non quelle ancora presenti nel buffer. Allo stesso modo, se si sta facendo dell'input/output interattivo bisognerà -tenere presente le caratteristiche delle operazioni di \textit{flush} dei -dati, poiché non è detto che ad una scrittura sullo stream corrisponda una -immediata scrittura sul dispositivo. +tenere presente le caratteristiche delle operazioni di scarico dei dati, +poiché non è detto che ad una scrittura sullo stream corrisponda una immediata +scrittura sul dispositivo. Per rispondere ad esigenze diverse, lo standard definisce tre distinte modalità in cui può essere eseguita la bufferizzazione, delle quali occorre essere ben @@ -177,18 +177,18 @@ chiarimenti e attenzioni per quel che concerne il suo funzionamento. Come gi accennato nella descrizione, \emph{di norma} i dati vengono inviati al kernel alla ricezione di un carattere di a capo; questo non è vero in tutti i casi, infatti, dato che le dimensioni del buffer usato dalle librerie sono fisse, se -le si eccedono si può avere un \textit{flush} dei dati anche prima che sia -stato inviato un carattere di \textit{newline}. +le si eccedono si può avere uno scarico dei dati anche prima che sia stato +inviato un carattere di \textit{newline}. Un secondo punto da tenere presente, particolarmente quando si ha a che fare con I/O interattivo, è che quando si effettua una lettura su uno stream che comporta l'accesso al kernel\footnote{questo vuol dire sempre se lo stream da - cui si legge è in modalità \textit{unbuffered}} viene anche eseguito il -\textit{flush} di tutti i buffer degli stream in scrittura. + cui si legge è in modalità \textit{unbuffered}} viene anche eseguito lo +scarico di tutti i buffer degli stream in scrittura. In \secref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle -opportune funzioni per controllare le modalità di bufferizzazione ed il -\textit{flush} dei dati. +opportune funzioni per controllare le modalità di bufferizzazione e lo scarico +dei dati. @@ -308,6 +308,10 @@ usare una delle funzioni \func{fseek}, \func{fsetpos} o \func{rewind}. Anche una operazione nominalmente nulla come \func{fseek(file, 0, SEEK\_CUR)} è sufficiente a garantire la sincronizzazione. +Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione +fintanto che non si è effettuat + + Uno stream viene chiuso con la funzione \func{fclose} il cui prototipo è: \begin{prototype}{stdio.h}{int fclose(FILE * stream)} Chiude lo stream \param{stream}. @@ -318,6 +322,11 @@ Uno stream viene chiuso con la funzione \func{fclose} il cui prototipo funzione che è fallita (\func{close}, \func{write} o \func{fflush}). \end{prototype} +La funzione effettua uno scarico di tutti i dati presenti nei buffer di uscita +e scarta tutti i dati in ingresso, se era stato allocato un buffer per lo +stream questo verrà rilasciato. La funzione effettua lo scarico solo per i +dati presenti nei buffer in user space usati dalle \acr{glibc}; se si essere +sicuri che il kernel forzi la scrittura su disco occorrà effettuare . \subsection{Lettura e scrittura su uno stream} @@ -363,11 +372,3 @@ stream; se non si \subsection{Efficienza} \label{sec:file_stream_efficiency} - - - - - - - - diff --git a/fileunix.tex b/fileunix.tex index b9d7219..ebba51b 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -353,7 +353,9 @@ secondo le tre modalit ciascuno di questi bit, dette costanti possono essere combinate fra di loro con un OR aritmetico per costruire il valore (in forma di maschera binaria) del parametro \var{flags} da passare alla \func{open} per specificarne il -comportamento. +comportamento. I due flag \macro{O\_NOFOLLOW} e \macro{O\_DIRECTORY} sono +estensioni specifiche di Linux, e deve essere usata definita la macro +\macro{\_GNU\_SOURCE} per poterli usare. Nelle prime versioni di unix i flag specificabili per \func{open} erano solo quelli relativi alle modalità di accesso del file. Per questo motivo per @@ -392,7 +394,7 @@ aperto, tutte le risorse nella file table vengono rilasciate. Infine se il file descriptor era l'ultimo riferimento ad un file su disco quest'ultimo viene cancellato. -Si ricordi che quando un processo termina anche tutti i sui file descriptor +Si ricordi che quando un processo termina anche tutti i suoi file descriptor vengono chiusi, molti programmi sfruttano questa caratteristica e non usano esplicitamente \func{close}. In genere comunque chiudere un file senza controllarne lo stato di uscita è errore; infatti molti filesystem @@ -406,9 +408,10 @@ quote su disco. In ogni caso una \func{close} andata a buon fine non garantisce che i dati siano stati effettivamente scritti su disco, perché il kernel può decidere di ottimizzare l'accesso a disco ritardandone la scrittura. L'uso della funzione -\func{sync} effettua esplicitamente il \emph{flush} dei dati, ma anche in -questo caso resta l'incertezza dovuta al comportamento dell'hardware (che a -sua volta può introdurre ottimizzazioni dell'accesso al disco). +\func{sync} (vedi \secref{sec:file_sync}) effettua esplicitamente il +\emph{flush} dei dati, ma anche in questo caso resta l'incertezza dovuta al +comportamento dell'hardware (che a sua volta può introdurre ottimizzazioni +dell'accesso al disco). \subsection{La funzione \func{lseek}} @@ -771,6 +774,71 @@ assenza, diventa atomica essendo svolta tutta all'interno di una singola \func{open}. +\subsection{La funzioni \func{sync} e \func{fsync}} +\label{sec:file_sync} + +Come accennato in \secref{sec:file_close} tutte le operazioni di scrittura +sono in genere bufferizzate dal kernel, che provvede ad effettuarle in maniera +asincrona (ad esempio accorpando gli accessi alla stessa zona del disco) in un +secondo tempo rispetto al momento della esecuzione della \func{write}. + +Per questo motivo, quando è necessaria una sincronizzazione dei dati, il +sistema mette a disposizione delle funzioni che provvedono a forzare lo +scarico dei dati dai buffer del kernel\footnote{come già accennato neanche + questo da la garanzia assoluta che i dati siano integri dopo la chiamata, + l'hardware dei dischi è in genere dotato di un suo meccanismo interno che + può ritardare ulteriormente la scrittura effettiva.}. La prima di queste +funzioni è \func{sync} il cui prototipo è: +\begin{prototype}{unistd.h}{int sync(void)} + + La funzione sincronizza buffer della cache dei file col disco. + + La funzione ritorna sempre zero. +\end{prototype} +\noindent i vari standard prevedono che la funzione si limiti a far partire +le operazioni, ritornando immediatamente; in Linux (dal kernel 1.3.20) invece +la funzione aspetta la conclusione delle operazioni di sincronizzazione del +kernel. + +La funzione viene usata dal comando \cmd{sync} quando si vuole forzare +esplicitamente lo scarico dei dati su disco, o dal demone di sistema +\cmd{update} che esegue lo scarico dei dati ad intervalli di tempo fissi: il +valore tradizionale per l'update dei dati è ogni 30 secondi, ma in Linux era +di 5 secondi; con le nuove versioni poi, è il kernel che si occupa +direttamente di tutto quanto. + +Quando si vogliono scaricare soltanto i dati di un file (ad esempio essere +sicuri che i dati di un database sono stati registrati su disco) si possono +usare le due funzioni \func{fsync} e \func{fdatasync}, i cui prototipi sono: +\begin{functions} + \headdecl{unistd.h} + \funcdecl{int fsync(int fd)} + Sincronizza dati e metadati del file \param{fd} + \funcdecl{int fdatasync(int fd)} + Sincronizza i dati del file \param{fd}. + + La funzione ritorna 0 in caso di successo e -1 in caso di errore, nel qual + caso i codici restituiti in \var{errno} sono: + \begin{errlist} + \item \macro{EINVAL} \param{fd} è un file speciale che non supporta la + sincronizzazione. + \end{errlist} + ed inoltre \macro{EBADF}, \macro{EROFS} e \macro{EIO}. +\end{functions} + +Entrambe le funzioni forzano la sincronizzazione col disco di tutti i dati del +file specificato, ed attendono fino alla conclusione delle operazioni; +\func{fsync} forza anche la sincronizzazione dei metadata dell'inode (i dati +di \var{fstat} come i tempi del file). + + +Si tenga presente che questo non comporta la sincronizzazione della directory +che contiene il file (e scrittura della relativa voce su disco) che deve +essere effettuata esplicitamente\footnote{in realtà con il filesystem + \acr{ext2}, quando questo viene montato con l'opzione \cmd{sync}, il kernel + provvede anche alla sincronizzazione automatica delle voci delle + directory.}. + \subsection{La funzioni \func{dup} e \func{dup2}} \label{sec:file_dup} @@ -940,7 +1008,15 @@ La maggior parte delle funzionalit poter essere affrontate in dettaglio a questo punto; saranno riprese più avanti quando affronteremo le problematiche ad esse relative. -Per determinare le modalità di accesso inoltre può essere necessario usare la +Per determinare le modalità di accesso inoltre è necessario estrarre i bit di +accesso (ottenuti con il comando \macro{F\_GETFL}); infatti la definizione +corrente non assegna bit separati a \macro{O\_RDONLY}, \macro{O\_WRONLY} e +\macro{O\_RDWR}\footnote{posti rispettivamente ai valori 0, 1 e 2}, per cui il +valore si ottiene eseguendo un AND binario del valore di ritorno di +\func{fcntl} con la maschera \macro{O\_ACCMODE} anch'essa definita in +\file{fcntl.h}. + + \subsection{La funzione \func{ioctl}} \label{sec:file_ioctl}