%%
%% Dispense corso amministrazione 
%%
%% Copyright (C) 2003-2018 Simone Piccardi and Truelite Srl.
%%
%% This work is licensed under the Creative Commons Attribution-ShareAlike 4.0
%% International License. To view a copy of this license, visit
%% \url{http://creativecommons.org/licenses/by-sa/4.0/} or send a letter to
%% Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
%%
%% S. Piccardi Sep. 2003
%% 
%% advadmin.tex: Amministrazione avanzata del sistema
%%
\chapter{Amministrazione avanzata del sistema}
\label{cha:advanced_admin}



\section{L'utilizzo del RAID}
\label{sec:disk_RAID} 

Tratteremo in questa prima sezione l'utilizzo dei sistemi RAID, una tecnologia
che permette di utilizzare i dischi a gruppi (detti \textit{array}) per
ottenere migliori prestazioni o una maggiore affidabilità; partiremo con una
introduzione teorica a questa tecnologia per poi vedere le varie modalità con
cui essa viene realizzata e può essere utilizzata con Linux.


\subsection{Introduzione}
\label{sec:RAID_intro}

La tecnologia RAID, acronimo che sta per \textit{Redundant Arrays of
  Inexpensive Disks}, nasce con un articolo pubblicato nel 1987 a Berkeley,
dove si descrivevano varie tipologie di \textit{disk array}. L'idea di base è
quella di combinare più dischi indipendenti di piccole dimensioni per ottenere
o prestazioni, o affidabilità o quantità di spazio disco superiori a quelle
ottenibili con un qualunque disco SLED (\textit{Single Large Expensive
  Drive}).

L'articolo presentava cinque diversi tipi di architetture RAID (da RAID-1 a
RAID-5) ciascuna delle quali prevedeva diversi gradi di ridondanza per fornire
tolleranza alla rottura e diversi gradi di prestazioni. A queste si è aggiunta
poi la notazione RAID-0 per indicare una configurazione senza ridondanza.

Oggigiorno alcune delle configurazioni previste nell'articolo non sono più
supportate (se non in sistemi specializzati), e non le prenderemo neanche in
considerazione, ne sono poi emerse altre come la combinazione del RAID-0 con
il RAID-1, denominata RAID-10, o quella definita \textit{linear}. Con il
kernel 2.6.x inoltre è stato introdotto anche il RAID-6 analogo al RAID-5 ma
in grado di assicurare una maggiore affidabilità. In generale comunque ci si
suole riferire a queste configurazioni con il nome di \textsl{livelli}, quelli
che prenderemo in esame sono pertanto:
\begin{basedescript}{\desclabelwidth{1.8cm}\desclabelstyle{\nextlinelabel}}
\item[linear] In questo livello due o più dischi vengono combinati in un
  singolo dispositivo. I dischi sono semplicemente accodati uno sull'altro,
  così che scrivendo in maniera lineare prima verrà riempito il primo e poi i
  successivi. La dimensione dei singoli dischi in questo caso è del tutto
  irrilevante.

  Questo livello non assicura nessun tipo di ridondanza, e se uno dei dischi si
  rompe si perderanno probabilmente tutti i dati. Data la modalità di
  scrittura comunque si perderanno solo i dati presenti nel disco rotto, e
  qualche forma di recupero potrebbe comunque essere possibile.

  Questa configurazione non migliora le prestazioni di lettura o scrittura
  sulla singola operazione, ma quando più utenti accedono all'array si può
  avere una distribuzione del carico sui vari dischi, qualora per un caso
  fortuito vengano eseguiti degli accessi a dati posti su dischi diversi.
  
\item[RAID-0] Questo livello è anche chiamato \textit{stripe mode}; in questo
  caso i dischi dovrebbero avere la stessa dimensione, anche se non è
  strettamente necessario. In questo caso le operazioni sull'array vengono
  distribuite sui singoli dischi. Se si scrive un blocco di dati questo verrà
  suddiviso in \textsl{strisce} (le \textit{stripes}, appunto) di dimensione
  predefinita che vengono scritte in sequenza su ciascuno dei vari dischi che
  compongono l'array: una striscia sul primo, poi sul secondo, ecc. fino
  all'ultimo per poi ricominciare con il primo. La dimensione delle strisce
  di norma viene definita in fase di creazione dell'array, ed è uno dei
  parametri fondamentali per le prestazioni dello stesso. La capacità totale
  resta la somma di quella dei singoli dischi.
  
  In questo modo le prestazioni di lettura e scrittura possono essere
  notevolmente aumentate, in quanto le operazioni vengono eseguite in
  parallelo su più dischi, e se i dischi sono veloci ed in numero sufficiente
  si può facilmente saturare la capacità del bus, o se quest'ultimo è veloce
  si può ottenere una banda passante totale pari alla somma di quella dei
  singoli dischi.
  
  Se è presente un disco di dimensioni maggiori degli altri si potrà
  continuare ad accedere operando solo sullo spazio presente sulla parte
  finale dello stesso, ma in questo caso si opererà su un solo disco, e non si
  avrà quindi nessun miglioramento delle prestazioni per quanto riguarda i
  dati che vanno a finire su di esso.
  
  Come nel caso precedente questo livello non fornisce nessuna ridondanza. La
  rottura di un disco comporta la perdita totale di tutti i dati, compresi
  pure quelli sugli altri dischi, dato che in questo caso non esistono, a
  differenza di \textit{linear}, blocchi di dati continui più lunghi della
  dimensione di una striscia. In questa modalità l'MTBF (sigla che sta per
  \textit{Mean Time Between Failure}) diminuisce proporzionalmente al numero
  di dischi dell'array in quanto la probabilità di fallimento dell'array è
  equivalente a quella di un singolo disco moltiplicata per il numero dei
  dischi che compongono l'array.

  
\item[RAID-1] Questo è il primo livello che fornisce della ridondanza.
  Richiede almeno due dischi per l'array e l'eventuale presenza di dischi di
  riserva. Inoltre i dischi devono essere tutti uguali, se sono diversi la
  dimensione dell'array sarà quella del più piccolo dei dischi. I dati vengono
  scritti in parallelo su tutti i dischi che compongono l'array, pertanto
  basti che sopravviva anche un solo disco dell'array perché i dati siano
  intatti, in quanto ciascun disco ne ha una copia completa.  Gli eventuali
  dischi di riserva vengono utilizzati in caso di fallimento di un disco
  dell'array, per dare inizio ad una ricostruzione immediata dell'array
  stesso.
  
  Con questo livello di RAID si aumenta l'affidabilità in quanto la
  probabilità di fallimento dell'array è equivalente a quella di un singolo
  disco divisa per il numero dei dischi dell'array. In realtà poi è ancora
  minore, in quanto la probabilità che i dischi falliscano tutti insieme è
  ancora minore, per cui basta sostituire un disco rotto per recuperare
  l'intera funzionalità dell'array.
  
  Come controparte per l'affidabilità le prestazioni di scrittura di un RAID-1
  sono in genere peggiori di quelle del singolo disco, in quanto i dati devono
  essere scritti in contemporanea su più dischi, e se questi sono molti (e si
  usa una implementazione software) facendo passare tante copie si può
  superare il limite di banda del bus su cui sono posti i dischi abbastanza
  facilmente. In questo caso i controller hardware hanno il vantaggio di
  gestire internamente la replicazione dei dati, richiedendo l'invio su bus di
  una sola copia.
  
  Le prestazioni in lettura sono invece migliori, non tanto sulla singola
  lettura, ma quando ci sono molte letture contemporanee e spostamenti sui
  dati. In tal caso infatti i dati possono essere letti in parallelo da dischi
  diversi, e si può approfittare del diverso posizionamento delle testine sui
  dischi per leggere i dati da quello che deve compiere un minore spostamento
  delle testine.\footnote{è caratteristica comune degli hard disk avere tempi
    di risposta nettamente diversi per la lettura sequenziale di dati,
    rispetto al posizionamento (il cosiddetto \textit{seek time}).}
  
\item[RAID-4] Benché disponibile è senz'altro il meno usato. Necessita di tre
  o più dischi. Mantiene delle informazioni di recupero su un disco di
  \textsl{parità}, ed utilizza gli altri in RAID-0. I dischi devono essere di
  dimensioni identiche, altrimenti l'array avrà la dimensione del più piccolo
  di essi. Se uno dei dischi in RAID-0 si rompe è possibile utilizzare le
  informazioni di recupero del disco di \textsl{parità} per ricostruire i dati
  in maniera completa. Se si rompono due dischi si perderanno invece tutti i
  dati.
  
  Questo livello cerca di bilanciare i vantaggi di affidabilità del RAID-1 con
  le prestazioni del RAID-0, ma non viene usato molto spesso però perché il
  disco di parità viene a costituire un collo di bottiglia in quanto comunque
  tutte le informazioni devono esservi replicate, l'unico caso di impiego
  reale è quello di un disco veloce affiancato ad un gruppo di dischi più
  lenti.
  
\item[RAID-5] Come per il RAID-4 anche in questo caso si cercano di ottenere
  sia vantaggi di affidabilità che quelli di prestazioni, ed è il più usato
  quando si hanno più di due dischi da mettere in RAID. Anche per il RAID-5
  sono necessari almeno tre dischi, ma in questo caso, per evitare il problema
  del collo di bottiglia, le informazioni di \textsl{parità}, queste vengono
  distribuite su tutti i dischi che fanno parte dell'array. In questo modo
  anche se uno dei dischi si rompe le informazioni di parità presenti sugli
  altri permettono di mantenere intatti i dati. Inoltre se si sono inseriti dei
  dischi di riserva la ricostruzione del disco rotto o indisponibile viene
  fatta partire immediatamente. Se però si rompono due dischi i dati sono
  perduti.
  
  Il RAID-5 presenta inoltre, dato che i dati sono comunque distribuiti su più
  dischi, gli stessi vantaggi nella lettura presentati dal RAID-0. In
  scrittura invece le prestazioni sono meno predicibili, e le operazioni
  possono essere anche molto costose, quando richiedono pure le letture
  necessarie al calcolo delle informazioni di parità, o dell'ordine di quelle
  del RAID-1.  In generale comunque le prestazioni aumentano sia in lettura
  che in scrittura. Inoltre nel caso di RAID software è richiesto un certo
  consumo di risorse (sia di memoria che di CPU) per il calcolo delle
  informazioni di parità.
  
\item[RAID-10] Si suole definire così una configurazione in cui si effettua un
  RAID-0 di più array configurati in RAID-1. In questo modo si ottiene sia la
  ridondanza del RAID-1 che l'aumento di prestazioni del RAID-0.  Rispetto al
  RAID-5 ha il vantaggio che possono rompersi anche più dischi, ma fintanto
  che ne resta almeno uno attivo nei due RAID-1 le informazioni saranno
  integre.  Il tutto al prezzo di un numero molto maggiore di dischi per
  ottenere la stessa capacità.

\item[RAID-6] È concettualmente identico al RAID-5, di cui presenta le stesse
  caratteristiche funzionali, ma prevede che le informazioni di parità siano
  distribuite su due dischi aggiuntivi, così che sia possibile sopportare la
  rottura contemporanea di due dischi anziché uno solo.\footnote{evento che si
    è dimostrato tutt'altro che improbabile; i dischi di uno stesso produttore
    infatti, specie se provenienti dalla stessa catena di produzione, hanno
    dimostrato di avere una durata molto simile, cosa che comporta assai
    frequentemente delle rotture se non contemporanee comunque molto
    ravvicinate fra loro, con il rischio di non fare in tempo a sostituire un
    disco rotto prima che si rompa anche il secondo.} Rispetto al RAID-5 ha il
  vantaggio di una maggiore ridondanza dato che possono rompersi anche due
  dischi in contemporanea, mantenendo l'integrità dei dati fintanto che gli
  altri restano attivi. Il tutto al prezzo di dover usare un disco in più
  rispetto al RAID-5 per ottenere la stessa capacità.

\end{basedescript}

Un altro concetto relativo alla gestione del RAID, che si applica in genere ai
livelli che forniscono ridondanza, come RAID-1, RAID-5 e RAID-6, è quello dei
cosiddetti \textsl{dischi di riserva}, o \textit{spare disk}. In questo caso
si tratta di dischi che possono essere associati ad un array RAID senza però
venirne a far parte come membri attivi. Il loro scopo, come dice il nome, è
quello di essere usati come riserva quando uno dei dischi attivi si dimostra
difettoso. In questo caso è previsto che la implementazione del RAID si
accorga del problema ed inizi immediatamente ed in maniera automatica la
ricostruzione dell'array utilizzando il disco di riserva al posto di quello
difettoso, così da aumentare ulteriormente la salvaguardia dei dati.

Al giorno d'oggi lo scopo più comune dell'uso di un RAID è comunque quello di
proteggersi dal fallimento o dalla rottura di un disco mantenendo
automaticamente la ridondanza delle informazioni. Per questo il RAID-0 non
deve mai essere usato in un sistema di produzione, perché il rischio di
fallimento hardware si moltiplica per il numero di dischi, e con questo quello
della perdita completa dei dati, cosa che normalmente non vale il limitato
guadagno di prestazioni che si potrebbe ottenere a meno che non si tratti di
dati mantenuti altrove e per i quali si deve fornire semplicemente un accesso
il più rapido possibile.

Si tenga presente infine che l'utilizzo di un livello di RAID che assicuri la
ridondanza non è mai un sostituto di una buona politica di backup. Un array
RAID infatti può proteggere dal fallimento dell'hardware di uno o più dischi,
ma non può nulla contro la corruzione di un filesystem, contro un utente che
cancella (intenzionalmente o meno) i dati, o contro un qualunque altro
incidente che distrugga l'intero array.



\subsection{Il RAID su Linux}
\label{sec:RAID_in_Linux}

In generale per poter creare un array di dischi in RAID ci sono due opzioni
fondamentali: RAID hardware o RAID software. Nel primo caso occorre poter
disporre di un supporto hardware, cioè di un controller per i dischi che
esegue le operazioni necessarie alla realizzazione del RAID al suo interno, e
presenti poi al sistema operativo l'insieme dei dischi come un dispositivo
unico.

In teoria un RAID hardware è l'opzione migliore sul piano delle prestazioni in
quanto non necessita di utilizzare delle risorse (CPU e memoria) della
macchina per gestire il RAID e consente di eseguire il trasferimento di dati
una volta sola (dal sistema al dispositivo hardware). In genere però richiede
parecchie risorse (specie per i controller RAID SCSI di fascia alta) dal punto
di vista del portafoglio.

Inoltre la superiorità di prestazioni in certi casi è solo teorica, molti
controller hardware (specie quelli IDE o serial ATA disponibili a costi
limitati) si sono rivelati essere molto più lenti dell'implementazione del
RAID software di Linux, sia per la scarsa potenza dei processori utilizzati
che per la scarsa qualità del software della scheda.\footnote{cosa che
  talvolta li rende anche inaffidabili; questo non è vero in genere per i
  controller SCSI di fascia alta, che hanno però anche un livello di costi
  totalmente diverso.} Questo, unito al fatto che in molti casi nei server la
CPU è una risorsa meno rilevante rispetto alla stabilità e alla sicurezza
dell'I/O su disco, ha fatto sì che l'opzione del RAID software sia
estremamente competitiva nella maggior parte dei casi.

A questo si aggiunge poi il problema che alcuni controller hardware usano
implementazioni proprietarie nella gestione dei dati del RAID e di come questi
sono salvati su disco. Questo finisce poi col rendere impossibile riutilizzare
i dati contenuti sugli stessi dischi su controller di marca diversa, e
talvolta anche su versioni diverse di schede della stessa marca. Tutto ciò non
è ovviamente mai vero nel caso del RAID software fatto dal kernel, che è in
grado di riutilizzare i dischi qualunque sia la scheda su cui questi sono
montati.

In ogni caso Linux supporta vari controller RAID hardware, sia SCSI che IDE
che Serial ATA.  Nel caso di controller SCSI in molti casi è cura del
controller stesso presentare tutto l'array RAID come un singolo disco, che
pertanto sarà visto semplicemente con uno dei nomi associati ai dischi SCSI
(come \texttt{/dev/sda}). In tal caso le operazioni di gestione del RAID sono
demandate al firmware della relativa scheda e dipendono ovviamente da
quest'ultima, per cui in genere è necessario effettuare la configurazione del
RAID all'avvio della macchina operando all'interno del BIOS con l'interfaccia
messa a disposizione dalla scheda stessa.

Per alcuni controller RAID dedicati esistono dei driver specifici disponibili
nella sezione \texttt{Block Devices} della configurazione del kernel. In
questo caso i dispositivi RAID sono in genere accessibili attraverso opportune
sottodirectory o file di dispositivo sotto \texttt{/dev} che dipendono dal
tipo di controller. Ad esempio per il DAC Mylex viene usata una directory
\texttt{rd} mentre per gli array Compaq vengono usate, a seconda del tipo le
directory \texttt{ida} e \texttt{cciss}.  In questi casi i singoli array
vengono identificati per ``\textsl{canale}'' (spesso i controller supportano
più di una singola catena SCSI) e per ``\textsl{disco}'', un dispositivo
tipico di un array è sempre nella forma \texttt{/dev/rd/c0d0} che indica il
primo array sul primo canale. Una volta partizionato l'array (che a questo
punto viene visto come un altro disco) le partizioni saranno accessibili con
nomi del tipo \texttt{/dev/ida/c0d0p1}.

Nel caso di RAID su IDE non ci sono canali, ed i dispositivi sono accessibili,
una volta attivato il relativo supporto, che è nella sezione
\texttt{ATA/IDE/MFM/RLL support}, attraverso i file di dispositivo generici
disposti nella directory \texttt{/dev/ataraid}, i cui nomi sono analoghi ai
precedenti, soltanto che non presentano un numero di canale; si avrà cioè ad
esempio qualcosa del tipo di \texttt{/dev/ataraid/d0p1}. Nel caso di Serial
ATA di nuovo alcuni controller consentono di utilizzare una forma di RAID
hardware presentando al kernel l'array RAID come un singolo dispositivo; di
nuovo verranno visti come un disco SCSI. Si tenga presente che in molti casi
le prestazioni e l'affidabilità di queste schede a basso costo si sono
dimostrate molto limitate, tanto da sconsigliarne comunque l'uso a favore del
supporto software presente nel kernel.

Per quando non si dispone di un supporto hardware Linux fornisce un supporto
software, attivabile nella sezione \texttt{Multiple device driver support
  (RAID and LVM)}, che supporta la creazione di RAID-0, RAID-1, RAID-4,
RAID-5, RAID-6, RAID-10 (questi ultimi sui kernel più recenti) e
\textit{linear}.  È cioè possibile far costruire al kernel stesso degli array
utilizzando qualunque tipo di dispositivo a blocchi. Dato che gli stessi RAID
software sono a loro volta dispositivi a blocchi, è possibile riutilizzarli
per metterli in RAID fra di loro, pertanto è possibile creare a mano un
RAID-10 mettendo semplicemente in RAID-0 un precedente array software creato
in RAID-1. Una volta costruiti gli array si potrà accedere ad essi con i file
di dispositivo \texttt{/dev/md\textsl{N}} dove \texttt{N} è un numero
progressivo (in genere si parte da zero) associato a ciascun dispositivo RAID
in fase di creazione.

A parte abilitare il supporto nel kernel (cui abbiamo accennato in
sez.~\ref{sec:kernel_compile}), per l'utilizzo del RAID software è necessario
utilizzare anche gli opportuni programmi in user space. Fino al kernel 2.4 di
questi esistevano due versioni, i \texttt{raidtools} e il programma
\texttt{mdadm}. Con i kernel della serie 2.6 tutto viene gestito con
\texttt{mdadm} che è un singolo programma che raccoglie al suo interno tutte
le funzionalità che prima erano suddivise nei vari componenti dei
\texttt{raidtools}. Questi oggi sono totalmente deprecati e non sono più
disponibili in tutte le distribuzioni più recenti.


%%
%% ### OBSOLETE BEGIN ###
%% Materiale obsoleto sui raidtools
%%
\ifx\obsoletesection\undefined
\relax
\else

\subsection{Il RAID software con i \texttt{raidtools}}
\label{sec:RAID_raidtools}

Come accennato i \texttt{raidtools} utilizzano nelle loro operazioni un
apposito file di configurazione, \index{configurazione!\texttt{/etc/raidtab}}
\texttt{/etc/raidtab}, che contiene le definizioni di tutti gli array. Il file
è diviso in sezioni che definiscono i vari array, identificati dalla direttiva
\texttt{raiddev}, che prende come parametro il nome del dispositivo da
utilizzare per accedere ad esso. Una volta che si è definito un array lo si
può riutilizzare (in successive direttive \texttt{raiddev}.  Un esempio di
questo file, preso dalla pagina di manuale, è il seguente:
\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm]
#
# sample raiddev configuration file
# 'old' RAID0 array created with mdtools.
#
raiddev /dev/md0
    raid-level              0
    nr-raid-disks           2
    persistent-superblock   0
    chunk-size              8
    device                  /dev/hda1
    raid-disk               0
    device                  /dev/hdb1
    raid-disk               1
raiddev /dev/md1
    raid-level              5
    nr-raid-disks           3
    nr-spare-disks          1
    persistent-superblock   1
    parity-algorithm        left-symmetric
    device                  /dev/sda1
    raid-disk               0
    device                  /dev/sdb1
    raid-disk               1
    device                  /dev/sdc1
    raid-disk               2
    device                  /dev/sdd1
    spare-disk              0
\end{Verbatim}

La sintassi del file è molto semplice, righe vuote o inizianti per
``\texttt{\#}'' vengono ignorate, ogni riga valida contiene una direttiva
seguita da un parametro che ne specifica il valore.  Alla definizione di una
sezione con \texttt{raiddev} devono seguire le altre direttive che specificano
di che tipo di array di tratta. La principale è \texttt{raid-level}, che
prende come parametro il numero di livello: i valori possibili sono
\texttt{0}, \texttt{1}, \texttt{4} o \texttt{5}) oppure \texttt{linear}. A
questa segue di solito la direttiva \texttt{nr-raid-disks} che indica il
numero di dischi dell'array. Per i livelli che supportano dei dischi di
riserva (vale a dire RAID-5 e RAID-1) se ne può specificare il numero con
\texttt{nr-spare-disks}.

Per ciascuna componente dell'array si deve poi specificare con la direttiva
\texttt{device} qual'è il file di dispositivo con cui vi si accede. Questo può
essere un qualunque dispositivo a blocchi, ivi compreso un altro RAID, purché
questo sia già stato definito in una precedente sezione di
\texttt{/etc/raidtab}. Ad una direttiva \texttt{device} deve seguire una
direttiva \texttt{raid-disk} che ne specifica la posizione nell'array (in
ordine progressivo, a partire da 0). 

Gli eventuali dischi di riserva devono essere anch'essi dichiarati con
\texttt{device}, e poi specificati con la direttiva \texttt{spare-disk}. Nel
caso di RAID-4 esiste anche la direttiva di specificazione
\texttt{parity-disk} che identifica il disco con le informazioni di parità.
Devono essere specificate tante direttive \texttt{device} quanti sono i dischi
che si è indicato (con \texttt{nr-raid-disks} e \texttt{nr-spare-disks}) fare
parte dell'array.

Oltre a queste che sono fondamentali per definire la struttura di una array,
esistono una serie di direttive opzionali che permettono di configurare altre
caratteristiche del RAID.  Ad esempio l'uso della direttiva
\texttt{persistent-superblock} permette di salvare le informazioni relative
alla configurazione di un array in tutte le partizioni che ne fanno parte, in
un apposito blocco di dati, il \textit{persistent superblock} appunto, detto
così in quanto in questo modo le informazioni sull'array sono sempre
disponibili, anche quando non si può accedere ad \texttt{/etc/raidtab} (ad
esempio quando si ha la partizione radice sul RAID). I valori possibili sono
1 e 0 che rispettivamente attivano e disattivano l'uso del \textit{persistent
  superblock}.

Questa funzionalità è essenziale, se si è compilato il relativo supporto del
kernel, ad attivare anche l'autorilevamento del RAID all'avvio del kernel,
occorre però anche aver marcato le partizioni che fanno parte di un array come
di tipo \texttt{0xFD}; in tal caso infatti il kernel riconosce la partizione
come componente di un RAID, e legge dal \textit{persistent superblock} tutte
le informazioni necessarie per attivarlo.

Un'altra direttiva importante è \texttt{chunk-size} che dice le dimensioni, in
kilobyte, delle \textit{stripe} in cui vengono divisi i dati scritti
sull'array per i livelli che supportano lo \textit{striping}.  Questa non ha
nessun significato né per il RAID-1 né per il linear, perché in entrambi i
casi i dati vengono comunque scritti (rispettivamente su entrambi o su uno dei
dischi) qualunque sia la loro dimensione, ma negli altri casi questo dice la
dimensione delle \textsl{strisce} in cui vengono divisi i dati inviati su
dischi consecutivi.

Infine è molto utile la direttiva \texttt{failed-disk} che permette di creare
un array inserendoci un dispositivo senza che questo venga effettivamente
utilizzato; in sostanza questa direttiva marca il dispositivo suddetto come
\textsl{rotto}, e così diventa possibile ad esempio utilizzare il suddetto
dispositivo ed al contempo essere in grado anche di montare il dispositivo
RAID che userà i restanti dischi. È in questo modo che di solito si effettua
una installazione che usi come directory radice un array: prima si installa su
un disco normale, poi si crea l'array (di cui fa parte anche detto disco, ma
come \texttt{failed-disk}) e si copia su di esso tutto il sistema. Riavviando
ed usando l'array come radice si potrà successivamente aggiungere all'array il
disco usato per l'installazione, facendo fare la sincronizzazione dei dischi
al kernel.

Le altre principali direttive di \texttt{/etc/raidtab} sono riassunte in
tab.~\ref{tab:raidtab_options}; al solito l'elenco completo è nella pagina
di manuale, accessibile con \texttt{man raidtab}.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Direttiva} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{raiddev}       & introduce la sezione che definisce un array, 
                             prende come parametro il relativo file di
                             dispositivo.\\
    \texttt{raid-level}    & indica il tipo di RAID da utilizzare.\\ 
    \texttt{nr-raid-disks} & indica il numero di dischi che costituiscono 
                             direttamente l'array. \\
    \texttt{nr-spare-disks}& indica il numero di dischi di riserva inseriti
                             nell'array.\\
    \texttt{persistent-superblock} & registra le informazioni sull'array in un
                             apposito settore sui dispositivi sottostanti.\\
    \texttt{chunk-size}    & dimensione delle \textsl{strisce} (per le
                             modalità RAID che le supportano).\\
    \texttt{device}        & indica uno dei dispositivi costituenti l'array.\\
    \texttt{raid-disk}     & indica la posizione nell'array del precedente
                             dispositivo indicato con \texttt{device}.\\
    \texttt{spare-disk}    & indica la posizione nell'array del precedente
                             dispositivo indicato con \texttt{device} come
                             disco di riserva.\\
    \texttt{failed-disk}   & indica la posizione nell'array del precedente
                             dispositivo indicato con \texttt{device} come
                             disco rotto.\\
    \hline
  \end{tabular}
  \caption{Principali direttive di configurazione di \texttt{/etc/raidtab}.}
  \label{tab:raidtab_options}
\end{table}

Una volta definite le proprietà dei vari RAID in \texttt{/etc/raidtab} si può
inizializzare ed attivare ciascuno di essi con il comando \texttt{mkraid}, che
prende come parametro il file di dispositivo \texttt{/dev/mdX} che identifica
ciascun array. Con l'opzione \texttt{-c} si può specificare in file di
configurazione alternativo. Si tenga presente che l'operazione distrugge il
contenuto dei dischi, a meno che questi non siano marcati come
\texttt{failed-disk}; in genere comunque il comando rileva la presenza di
dati e si rifiuta di eseguire l'inizializzazione a meno che non la si forzi
con l'uso dell'opzione \texttt{-f}. Il comando rileva anche se i dispositivi
scelti sono già stati utilizzati per un altro RAID, nel qual caso per forzare
l'inizializzazione occorrerà usare l'opzione \texttt{-R}.

Una volta creato un array lo si può attivare con
\index{comando!\texttt{raidstart}} \texttt{raidstart} o si lo può
disattivare\footnote{ovviamente l'array non deve essere in uso.}  con
\index{comando!\texttt{raidstop}} \texttt{raidstop}; entrambi i comandi
vogliono come argomento il dispositivo da attivare (come identificato in
\texttt{/etc/raidtab}) oppure si può usare l'opzione \texttt{-a} per operare
su tutti gli array definiti. Anche per questi comandi si può utilizzare un
file di configurazione alternativo specificabile con l'opzione \texttt{-c};
per tutti i dettagli si faccia al solito riferimento alla pagina di manuale.

Una volta che si è creato ed attivato un array se ne può controllare lo stato
sul file \index{filesystem~\texttt{/proc}!\texttt{/proc/mdstat}}
\texttt{/proc/mdstat} che riporta tutte le informazioni relative ai
dispositivi RAID presenti nel sistema; un esempio di questo file è il
seguente:
\begin{Verbatim}[fontsize=\footnotesize,frame=single,samepage=true,
  xleftmargin=1cm,xrightmargin=1.5cm]
oppish:~# cat /proc/mdstat
Personalities : [raid1]
read_ahead 1024 sectors
md0 : active raid1 hdc1[1] hda1[0]
      116214080 blocks [2/2] [UU]

unused devices: <none>
\end{Verbatim}
in cui è presente un solo array in RAID-1, sincronizzato e attivo; quando
invece si ha il caso di un array in cui alcuni dischi non sono attivi e devono
essere sincronizzati si avrà un risultato del tipo:
\begin{Verbatim}[fontsize=\footnotesize,frame=single,samepage=true,
  xleftmargin=1cm,xrightmargin=1.5cm]
server:~# cat /proc/mdstat
Personalities : [raid1]
read_ahead 1024 sectors
md0 : active raid1 hdc1[0] hda1[1]
      5855552 blocks [2/2] [UU]

md1 : active raid1 hdc2[2] hda2[1]
      69336448 blocks [2/1] [_U]
      [>....................]  recovery =  0.8% (581632/69336448) finish=183.7m
in speed=6232K/sec
md2 : active raid1 hdc3[2] hda3[1]
      4490048 blocks [2/1] [_U]
\end{Verbatim}
dove si hanno tre array RAID-1 costruiti con le prime tre partizioni di due
dischi, in cui è attivo solo il secondo disco (\texttt{/dev/hda}), e si vede
come il primo array sia integro, il sistema stia provvedendo alla
ricostruzione del secondo, ed il terzo abbia un solo disco attivo.


Una delle funzionalità più interessanti dell'uso di tecnologie RAID che
supportano la ridondanza (come RAID-1 e RAID-5) è quella per cui è possibile
continuare ad utilizzare il sistema anche senza utilizzare uno dei dischi. In
genere un disco diventa inutilizzabile in caso di problemi hardware, però
fintanto che fa parte dell'array sarà possibile sostituirlo. Per questo esiste
il comando \index{comando!\texttt{raidhotremove}} \texttt{raidhotremove} che
permette di forzare l'uscita di un disco dall'array (ovviamente il comando
funziona solo se i restanti dischi sono sufficienti a mantenere attivo
l'array). Il comando prende come argomenti il dispositivo dell'array seguito
da quello del disco da rimuovere.

L'uso di questo comando può servire ad esempio quando si vuole sostituire un
disco, una volta tolto il disco dall'array infatti lo si potrà rimuovere
(anche senza riavviare, se il dispositivo è \textit{hot-pluggable}) senza
problemi, e senza dover fermare l'array (cosa che ad esempio non sarebbe
possibile se su di esso si è posta la directory radice). In sostanza l'effetto
è lo stesso che si sarebbe ottenuto creando l'array con la direttiva
\texttt{failed-disk}, ma può essere ottenuto in qualunque momento.

Cosi come si può rimuovere un disco da un array, è possibile aggiungerne uno
usando il comando \index{comando!\texttt{raidhotadd}} \texttt{raidhotadd}; in
questo caso un disco non attivo (perché rimosso in precedenza o perché marcato
\texttt{failed-disk} quando si è creato l'array) può essere inserito a caldo
nell'array, questo permetterà ad esempio di sostituire un disco mettendone uno
nuovo, e non appena esso sarà reinserito nell'array il kernel provvederà
automaticamente ad effettuare la sincronizzazione del contenuto dello stesso
ricostruendo l'integrità dell'array, così come mostrato nel secondo esempio
del contenuto di \texttt{/proc/mdstat}.

%
%% ### OBSOLETE END ###
%% Materiale obsoleto sui floppy ed i relativi kernel
%%
\fi


\subsection{La gestione del RAID software}
\label{sec:RAID_mdadm}

Per la creazione di un RAID software occorre anzitutto disporre di un
opportuno numero di dischi da utilizzare come membri del RAID, questo
significa almeno 2 per il RAID-1, almeno 3 per il RAID-5 ed almeno 4 per
RAID-6 e RAID-10. Benché sia possibile utilizzare un intero disco come membro
di un array, è molto più comune utilizzare delle singole partizioni (cosa che
ad esempio nel caso del RAID-1 consente di riutilizzare direttamente anche il
singolo disco). Questo consente anche, suddividendo i dischi in partizioni
uguali, di creare più dispositivi RAID dallo stesso insieme di dischi, da
utilizzare nella stessa maniera in cui si usano le diverse partizioni di un
unico disco.

Si tenga presente però che non ha alcun senso usare due partizioni dello
stesso disco come membri di un RAID; infatti in tal caso gli stessi dati
verrebbero scritti su due parti diverse dello stesso disco e non si avrebbe
così alcuna ridondanza. Inoltre dato che i dati di un RAID vengono scritti in
contemporanea su tutti i membri dell'array una tale configurazione
comporterebbe uno stress notevole del disco che dovrebbe eseguire accessi
contemporanei su zone diverse, e quindi un grosso lavoro di spostamento delle
testine; le conseguenze sarebbero un enorme degrado delle prestazioni ed un
forte stress meccanico, con aumento della probabilità di rottura.

Una seconda considerazione deve essere fatta riguardo la configurazione
hardware dei dischi. Si deve infatti tener presente che con il RAID software i
dati vengono inviati in copia su ciascun disco, questo significa ad esempio
che se si hanno molti dischi veloci su un unico bus SCSI, si potrebbe
raggiungere il limite di banda passante del bus e non sfruttare a pieno la
velocità di trasferimento dei singoli dischi.

Un problema simile si ha quando si usano dischi IDE, in tal caso infatti se si
montano due dischi sullo stesso canale IDE essendo l'accesso al bus conteso le
prestazioni degradano dato che i dati possono essere inviati soltanto un disco
alla volta; inoltre se uno dei dischi si rompe questo può comportare anche il
blocco dell'intero canale, con il conseguente disastroso fallimento
dell'intero array.  Per questo motivo quando si usano dischi IDE questi devono
sempre essere posti su canali IDE diversi. Questo comunque non si applica al
Serial ATA, che non supporta il concetto di master/slave.

Si tenga presente infine che, a parte il caso del \texttt{linear}, per poter
creare un RAID occorrerà che i dischi (o le singole partizioni) che andranno a
far parte dell'array siano delle stesse dimensioni. In realtà questo non è
strettamente necessario, in quanto se si usano dischi o partizioni di
dimensioni diverse in fase di creazione del RAID verrà usata la più piccola di
quelle disponibili, e l'unico inconveniente potrà essere quello dello spreco
di un po' di spazio disco. 

Le cose però possono diventare molto più complicate in caso di sostituzione di
un disco: accade spesso infatti che le dimensioni dichiarate dai costruttori
siano tutt'altro che precise, ed è comune trovarsi con due dischi che solo
nominalmente sono della stessa dimensione, il problema è che se il nuovo disco
è anche solo leggermente più piccolo della dimensione usata per il RAID con il
vecchio, non è più possibile utilizzarlo.  Per questo c'è chi usa sempre una
partizione leggermente più piccola delle dimensioni reali del disco, per
lasciarsi un margine per casi di questo tipo.

Come accennato in sez.~\ref{sec:partitioning} le partizioni utilizzate per il
RAID software possono essere marcate come tali impostando un tipo specifico; i
valori possibili sono due, ``\texttt{fd}'' che identifica le vecchie
partizioni di tipo ``\textit{RAID autodetect}'' e'' \texttt{da}'' che è il
valore consigliato per le nuove partizioni (denominato ``\textit{non fs
  data}''). L'uso di ``\texttt{fd}'' infatti comporta da parte del kernel il
tentativo di assemblare e far partire automaticamente il RAID software quando
rileva una partizione di questo tipo,\footnote{questa funzionalità è comunque
  disponibile solo se il supporto è compilato all'interno del kernel e solo
  con certe versioni del RAID software, ed in particolare con la versione 0.90
  del cosiddetto \textit{RAID superblock}, che al momento (Aprile 2009) è
  ancora il default.}  cosa che non è detto sia sempre voluta, e che in certi
casi, come quello in cui si sposta un disco su un'altra macchina senza
cancellarlo, può creare danni notevoli se questo viene assemblato come parte
di un array già attivo. 

Per questo motivo questa funzionalità, creata per poter far partire
automaticamente un RAID da montare come radice, è attualmente deprecata (anche
se sempre disponibile) in favore dell'uso di un opportuno \textit{ramdisk} di
avvio (vedi sez.~\ref{sec:kernel_install}) contenente i programmi in grado di
assemblare il RAID in modo opportuno, ad esempio facendo riferimento agli UUID
associati a ciascun dispositivo RAID software.

Come già accennato a partire dai kernel della serie 2.6 tutte le operazioni di
gestione del RAID software sono state demandate al programma
\index{comando!\texttt{mdadm}} \texttt{mdadm}; dato che detto programma è
disponibile anche per i kernel della serie 2.4 non tratteremo affatto i vecchi
\texttt{raidtools} il cui interesse ormai è esclusivamente storico. 

Una delle caratteristiche principali di \texttt{mdadm}, che lo distingue
nettamente dai \texttt{raidtools}, è quella di poter funzionare anche senza la
presenza di un file di configurazione; la scelta deriva dal fatto che quando
la radice è su RAID il contenuto di \texttt{/etc} non è accessibile senza aver
prima attivato il RAID stesso.

Il comando fa comunque riferimento al contenuto
\index{configurazione!\texttt{/etc/mdadm/mdadm.conf}}
\texttt{/etc/mdadm/mdadm.conf} o, se questo non esiste, di
\texttt{/etc/mdadm.conf}. In genere questo file viene utilizzato, oltre che
per impostare una serie di valori di default, per mantenere la lista degli
array presenti sulla propria macchina e viene sempre creato in fase di
installazione. Un esempio del suo contenuto è quello riportato dal seguente
estratto dalla versione presente su una Debian Lenny su cui sono stati creati
tre array RAID-1:
\begin{FileExample}[label=mdadm.conf]
# by default, scan all partitions (/proc/partitions) for MD superblocks.
# alternatively, specify devices to scan, using wildcards if desired.
DEVICE partitions

# auto-create devices with Debian standard permissions
CREATE owner=root group=disk mode=0660 auto=yes

# automatically tag new arrays as belonging to the local system
HOMEHOST <system>

# instruct the monitoring daemon where to send mail alerts
MAILADDR root

# definitions of existing MD arrays
ARRAY /dev/md0 level=raid1 num-devices=2 UUID=63492dc1:8eaa5c05:5fb94220:239df376
ARRAY /dev/md1 level=raid1 num-devices=2 UUID=fa83ab9c:8d008d80:ded268eb:c0534d8f
ARRAY /dev/md2 level=raid1 num-devices=2 UUID=e11003b2:7eda78aa:0e5f395c:9308b30d
\end{FileExample}

Il formato di \texttt{mdadm.conf} è quello tipico in cui le righe vuote e
quelle inizianti con il carattere ``\texttt{\#}'' vengono ignorate; le
configurazioni vengono specificate ponendo la parola chiave che identifica la
direttiva all'inizio della riga, seguita poi da eventuali parametri separati
da spazi o tabulazioni. Una riga che inizia con un carattere di spaziatura
viene considerata una prosecuzione della riga precedente. Le principali
direttive ed i loro parametri sono illustrate in tab.~\ref{tab:mdadm.conf}, le
parole chiavi ivi riportate possono essere scritte per intero o con una
abbreviazione di tre lettere. Al solito per l'elenco completo di direttive e
parametri ed i dettagli sul loro significato si può fare riferimento alla
pagina di manuale accessibile con \texttt{man mdadm.conf}.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{ARRAY}   & identifica un array, il primo parametro è il nome del
                       file di dispositivo ad esso
                       associato, seguito da una lista di parametri che
                       identificano le caratteristiche dell'array; questi sono
                       nella forma \texttt{chiave=valore} dove ciascuna chiave
                       identifica la caratteristica indicata dal corrispondente
                       valore, le principali chiavi sono: \texttt{uuid} che
                       indica l'UUID associato all'array, \texttt{level} che
                       indica il tipo di RAID, \texttt{num-devices} che indica 
                       il numero di componenti; per un elenco completo si
                       consulti la pagina di manuale.\\ 
    \texttt{DEVICE}  & indica la lista dei dispositivi che possono contenere
                       un componente di un array, questi possono essere
                       indicati tramite i rispettivi file di dispositivo,
                       usando anche i caratteri jolly del \textit{filename globbing},
                       alternativamente si può usare la parola chiave
                       \texttt{partitions} per indicare al comando di leggere
                       ed utilizzare il contenuto di
                       \texttt{/proc/partitions}.\\
    \texttt{CREATE}  & indica i permessi da assegnare al file di dispositivo
                       di un array quando questo viene creato in modalità
                       automatica (con l'opzione \texttt{-a} di
                       \texttt{-{}-create}); prevede l'uso di una serie di
                       parametri nella forma \texttt{chiave=valore}, di nuovo
                       si consulti la pagina di manuale per i dettagli, anche
                       se i nomi delle chiavi, come \texttt{user},
                       \texttt{group} o \texttt{mode} sono piuttosto
                       espliciti.\\
    \texttt{MAILADDR}& indica l'indirizzo email,  a cui inviare gli allarmi
                       quando \texttt{mdadm} viene eseguito in modalità
                       \textit{Monitor}.\\
    \texttt{HOMEHOST}& indica il nome della macchina usato come valore di
                       default per l'opzione \texttt{-{}-homehost} di
                       \texttt{mdadm}; può essere un nome a dominio o la
                       parola chiave \texttt{<system>} che la ottiene
                       direttamente dal sistema (si assumono noti i concetti
                       di nome a dominio e di nome della macchina che
                       tratteremo comunque in
                       sez.~\ref{sec:net_name_resolution}).\\ 
    \hline
  \end{tabular}
  \caption{Principali direttive di configurazione di \texttt{mdadm.conf}.}
  \label{tab:mdadm.conf}
\end{table}

Dato che tutti gli aspetti della gestione del RAID software vengono gestiti
con \texttt{mdadm}, le operazioni del comando sono state suddivise su sette
diverse modalità di utilizzo, riportate in tab.~\ref{tab:mdadm_operation}. Le
prime cinque modalità sono da attivare esplicitamente tramite l'uso delle
corrispondenti opzioni, mentre la modalità \textit{Manage} è sottintesa se si
passa come primo argomento prima di ogni opzione il file di dispositivo di un
array o se la prima opzione è \texttt{-{}-add}, \texttt{-{}-fail} o
\texttt{-{}-remove}. Tutte le restanti possibilità fanno capo alla modalità
\textit{Misc}.

\begin{table}[!htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|l|c|p{8cm}|}
    \hline
    \textbf{Modalità} & \multicolumn{2}{|c|}{\textbf{Opzione}} & 
           \textbf{Significato} \\
    \hline
    \hline
    \textit{Create}  &\texttt{-{}-create}  &\texttt{-C}&
           crea da zero un nuovo array di dischi, registrando sui singoli
           dischi le informazioni di gestione ad esso relative con
           l'installazione del cosiddetto \textsl{superblocco}.\\
    \textit{Build}   &\texttt{-{}-build}   &\texttt{-B}&
           costruisce ed attiva un array ignorando eventuali informazioni di
           gestione del \textsl{superblocco}, pertanto è possibile costruire un
           array con dischi anche completamente scorrelati fra loro
           distruggendo completamente i dati precedentemente presenti, inoltre
           per riavviare l'array occorre ricordarsi esattamente i dischi
           usati, è pertanto da usare esclusivamente quando si sa esattamente
           cosa si sta facendo.\\
    \textit{Assemble}&\texttt{-{}-assemble}&\texttt{-A}& 
           assembla un array precedentemente creato con la registrazione del
           \textsl{superblocco} sui singoli dispositivi; viene utilizzato per
           far partire un dispositivo RAID all'avvio.\\
    \textit{Grow}    &\texttt{-{}-grow}    &\texttt{-G}&
           consente di allargare o restringere un array, o di modificarne le
           caratteristiche. In pratica viene usato per modificare le
           dimensioni dei singoli componenti di un array o per cambiare il
           numero di dischi attivi per i RAID dei livelli 1, 4, 5 e 6.\\
    \textit{Monitor} &\texttt{-{}-monitor} &\texttt{-F}& 
           denominato anche \textit{Follow} (attivabile anche con
           \texttt{-{}-follow}) consente di tenere sotto osservazione lo stato
           di integrità di uno o più array; ha senso solo per gli array che
           supportano la ridondanza.\\
    \textit{Incr. Assembly}&\texttt{-{}-incremental}& \texttt{-I}&  
           una variante di \textit{Assemble} in cui si specificano i membri di
           un array uno alla volta invece che tutti insieme; viene in genere
           utilizzato per far partire un RAID quando questo è composto di
           dischi \textit{hot-plug} che possono essere riconosciuti in
           sequenza.\\ 
    \textit{Manage}  & -- & -- &  
           è la modalità in cui si può operare sui singoli componenti di un
           array, con operazioni come l'aggiunta di nuovi dischi di riserva,
           la rimozione dall'array di dischi difettosi e simili.\\
    \textit{Misc}    & -- & -- &  
           è la modalità utilizzata per tutte le operazioni di varia natura
           che non rientrano nelle categorie precedenti.\\
    \hline
  \end{tabular}
  \caption{Modalità di operazione di \texttt{mdadm}.}
  \label{tab:mdadm_operation}
\end{table}

In generale nella gestione del RAID il primo utilizzo di \texttt{mdadm} deve
essere effettuato in modalità \textit{Create} (con l'opzione \texttt{-C} o
\texttt{-{}-create}) per creare l'array a partire dalla serie di dischi che ne
fanno parte, a cui deve seguire il nome del file di dispositivo a cui l'array
sarà associato. Si tenga presente che in questo caso creare significa
predisporre su ciascuno dei membri di un array i dati che ne contengono le
caratteristiche e le informazioni di gestione, che sono mantenuti nel
cosiddetto \textsl{superblocco} (in inglese \textit{superblock}); una piccola
sezione di disco utilizzata per mantenere le informazioni relative all'array
di cui esso viene a far parte.\footnote{fino alla versione 0.90 questo era
  posto in coda al disco (o alla partizione), è stato poi spostato all'inizio
  e nell'ultima versione a 4K dall'inizio della partizione, è cura del RAID
  software evitare che lo spazio allocato per il \textsl{superblocco} venga
  sovrascritto dai dati.}  Fra queste la più importante è il valore dell'UUID
associato all'array, che è quello che poi può essere utilizzato in seguito per
farlo ripartire (al riavvio della macchina o qualora lo si fosse fermato), e
che compare fra i parametri della direttiva \texttt{ARRAY} di
\texttt{mdadm.conf}.

Sempre nel superblocco viene registrato il nome della macchina su cui si è
creato l'array, cosa che consente di evitare che questo venga attivato
automaticamente su una macchina diversa quando si usano le opzioni per la
partenza automatica dell'array. Il nome da usare viene impostato tramite la
direttiva \texttt{HOMEHOST} di \texttt{mdadm.conf} il cui default, come
mostrato nell'esempio precedente, è \texttt{<system>}, che indica di usare il
nome stesso della macchina. Il valore può però anche essere specificato
direttamente sulla riga di comando, soprassedendo quanto indicato con detta
direttiva, come argomento per l'opzione \texttt{-{}-homehost}, questa è una
delle opzioni generiche che possono essere usate in diverse modalità, il suo
compito è quello di indicare quale nome di macchina deve essere preso come
riferimento nei confronti di quello memorizzato sul superblocco.

Si tenga presente che nella gestione del RAID software la modalità
\textit{Create} deve essere impiegata soltanto una volta, quando si costruisce
l'array; in seguito infatti sarà sufficiente utilizzare le informazioni
permanenti registrate nel superblocco per fare ripartire l'array riassemblando
(come vedremo analizzando la modalità \textit{Assemble}) i vari dischi che ne
fanno parte. Si può però anche creare un array con la modalità \textit{Build}
in cui questo viene costruito senza registrare informazioni permanenti sui
suoi componenti; in tal caso non esistono controlli che permettono di evitare
di assemblare un array con dati non coerenti, e in caso di errore si rischia
ovviamente la perdita completa del contenuto dello stesso.

Una volta selezionata la modalità con \texttt{-{}-create} si deve specificare
come primo argomento il file di dispositivo che si vuole sia usato per
accedere all'array. Si può però usare l'opzione \texttt{-a} per richiedere una
allocazione dinamica dello stesso; in tal caso il dispositivo viene creato
sotto \texttt{/dev/md/} con un numero progressivo anche se il classico
\texttt{/dev/md\textsl{N}} viene fornito come link simbolico al precedente, si
deve poi specificare il tipo di RAID con l'opzione \texttt{-l} (o
\texttt{-{}-level}),\footnote{si ricordi che in caso di opzioni estese
  \texttt{mdadm} richiede che il relativo valore venga specificato in forma di
  assegnazione.} che richiede un successivo parametro che indichi il
``\textsl{livello}''. Questo deve essere specificato con una delle parole
chiave \texttt{stripe} o \texttt{mirror}, sinonimi rispettivamente di RAID-0 e
RAID-1, oppure specificando direttamente il valore del livello nella forma
\texttt{raid\textsl{N}} o semplicemente con \texttt{\textsl{N}}, (dove
\texttt{\textsl{N}} può assumere i valori 0, 1, 4, 5, 6 e 10).

L'altra opzione obbligatoria in fase di creazione di un array è \texttt{-n} (o
\texttt{-{}-raid-devices}) con cui si specifica il numero di dispositivi che
ne fanno parte; all'opzione deve essere fatta seguire una lista di altrettanti
file di dispositivo, si può però includere nella lista, per i livelli di RAID
che supportano la ridondanza, la parola chiave \texttt{missing},\footnote{il
  numero di volte in cui si può farlo dipende ovviamente dal tipo di RAID
  scelto: con i RAID-4 e RAID-5 una sola volta, con il RAID-6 due volte e
  quante volte si vuole con il RAID-1, ovviamente sarà necessario comunque
  indicare, per ciascuna di queste modalità, un numero di dispositivi
  sufficiente (almeno due, tranne che per il RAID-1).}  che consente di creare
un array senza la presenza di tutti i dischi dichiarati; ovviamente in questo
caso l'array creato sarà degradato fin dall'inizio, ma si potranno aggiungere
i dischi mancanti in seguito. 

Se si vogliono impostare anche dei dischi di riserva il loro numero deve
essere specificato con l'opzione \texttt{-x} (o \texttt{-{}-spare-devices})
cui come nel caso precedente si deve far seguire l'elenco dei relativi file di
dispositivo. In realtà si possono specificare le due opzioni ed i file di
dispositivo in un ordine qualunque, ma il numero di file di dispositivo
indicati (comprendendo fra questi eventuali \texttt{missing}) deve
corrispondere alla somma dei due numeri.

Pertanto un possibile esempio di creazione con \texttt{mdadm} di un
dispositivo RAID-1 a partire da due dischi IDE su cui si è usata una unica
partizione potrebbe essere il seguente:
\begin{Example}
mdadm --create /dev/md0 --level=mirror --raid-devices 2 /dev/hda1 /dev/hdc1
\end{Example}
mentre per la creazione di un RAID-5 a partire da tre dischi SCSI, con un
disco IDE come spare, sempre con una unica partizione, si potrebbe usare il
comando:
\begin{Example}
mdadm -C /dev/md1 -l 5 -n 3 /dev/sda1 /dev/sdb1 /dev/sdc1 -x 1 /dev/hda1
\end{Example}

Una volta creato un array con \texttt{-{}-create} questo viene immediatamente
attivato, questo comporta anche, per i livelli che supportano la ridondanza,
l'avvio della procedura di sincronizzazione dei dati dei vari dischi che lo
compongono (e il conseguente inizio di una frenetica attività sui dischi). Lo
stato degli array RAID presenti su una macchina può essere controllato tramite
il file \index{filesystem~\texttt{/proc}!\texttt{/proc/mdstat}}
\texttt{/proc/mdstat}.  Un esempio tipico di questo file, in una situazione
ordinaria di utilizzo di un array, è il seguente:
\begin{Console}
gethen:~# \textbf{cat /proc/mdstat}
Personalities : [raid1]
read_ahead 1024 sectors
md0 : active raid1 hdc1[1] hda1[0]
      116214080 blocks [2/2] [UU]

unused devices: <none>
\end{Console}
in cui viene mostrato lo stato su una macchina in cui è presente un solo array
RAID-1 composto da due dischi, sincronizzato e attivo.

In una situazione in cui un array è stato appena creato, e pertanto il
contenuto dei membri deve esser ancora sincronizzato, si avrà invece un
risultato analogo al seguente:
\begin{Console}
alterra:~# \textbf{cat /proc/mdstat}
Personalities : [raid1] 
md2 : active raid1 sda3[0] sdb3[1]
      7618816 blocks [2/2] [UU]
      [=========>...........]  resync = 45.0% (3433728/7618816) finish=63.2min speed=11018K/sec
\end{Console}
dove entrambi i dischi di un RAID-1 sono membri attivi dell'array, ma è in
corso la sincronizzazione dei loro contenuti.

Infine quando per un qualche motivo uno dei dischi che fa parte di un array
viene disattivato ed in seguito riattivato, il RAID dovrà essere ricostruito;
in tal caso si potrà avere invece un risultato analogo al seguente:
\begin{Console}
urras:~# \textbf{cat /proc/mdstat}
Personalities : [raid1]
read_ahead 1024 sectors
md0 : active raid1 hdc1[0] hda1[1]
      5855552 blocks [2/2] [UU]

md1 : active raid1 hdc2[2] hda2[1]
      69336448 blocks [2/1] [_U]
      [>....................]  recovery =  0.8% (581632/69336448) finish=183.7min speed=6232K/sec
md2 : active raid1 hdc3[2] hda3[1]
      4490048 blocks [2/1] [_U]
        resync=DELAYED
\end{Console}
dove viene mostrato lo stato di una macchina con tre array RAID-1 costituiti
dalle prime tre partizioni di due dischi IDE. 

In questo caso per un errore il secondo disco (\texttt{/dev/hdc}) era stato
disattivato, ed una volta riattivato \texttt{/proc/mdstat} mostra la
situazione in cui il primo array ha completato la risincronizzazione dei
dischi, il secondo è attivo con un solo disco ma in fase di ricostruzione ed
il terzo è attivo su un solo disco, in attesa di essere a sua volta
sincronizzato. Quando più array coinvolgono gli stessi dischi la
sincronizzazione viene sempre effettuata un array alla volta per evitare
eccessivo sforzo sulla meccanica del disco che altrimenti dovrebbe spostare le
testine da una partizione all'altra.

Il formato di \texttt{/proc/mdstat} prevede la presenza di una intestazione
che riporta la liste dei tipi di RAID utilizzati, seguita da una diversa
sezione per ciascun array presente. Nell'esempio precedente si ha
``\texttt{Personalities~:~[raid1]}'' dato che in quel caso veniva utilizzato
solo il RAID-1, altrimenti sarebbero state presenti anche voci corrispondenti
alle altre ``\textsl{personalità}''.

Ciascuna delle sezioni inizia con il nome del file di dispositivo ad esso
associato, seguito dallo stato e dalla lista dei dispositivi membri dell'array
indicati dai rispettivi file di dispositivo con fra parentesi quadra la
posizione dello stesso nell'array; il numero non significa nulla di per sé, è
solo un indice in una tabella, ma serve ad identificare la posizione del
dispositivo nella rappresentazione dei dispositivi attivi mostrata nelle righe
successive.

La riga seguente indica la dimensione, in blocchi, dell'array, seguita
dall'indicazione fra parentesi quadre del numero di dispositivi che ne fan
parte verso quelli attivi. Lo stato dei singoli viene rappresentato
graficamente anche da una stringa in cui ogni dispositivo attivo viene
rappresentato da una lettera ``\texttt{U}'', mentre i dispositivi non attivi
sono rappresentati dal carattere ``\texttt{\_}''. In caso di ricostruzione,
come nell'esempio precedente, viene mostrato anche una indicazione semigrafica
dello stato della procedura di ricostruzione con una stima del tempo mancante
alla sua conclusione.

Quando un array non è attivo, che questo sia avvenuto per il risultato di una
operazione esplicita di blocco,\footnote{ad esempio si può fermare un
  qualunque array, se questo non è in uso, con il comando \texttt{mdadm
    -{}-stop /dev/md0}.} o perché si è all'avvio del sistema, esso deve essere
esplicitamente riattivato\footnote{si ricordi che come accennato l'attivazione
  automatica viene eseguita dal kernel solo per i dispositivi marcati come
  membri di un RAID software nella tabella delle partizioni, e solo con la
  specifica versione del \textsl{superblocco}.} assemblando tutti i
dispositivi che ne fanno parte usando \texttt{mdadm} in modalità
\textit{Assemble}.  Le modalità con cui si può effettuare questa operazione
sono molteplici; la più diretta è quella in cui si passa come primo argomento
il nome del dispositivo associato all'array e come argomenti successivi
l'elenco dei dispositivi che ne fanno parte; ad esempio nel caso dell'array
RAID-1 creato con il primo dei comandi illustrati in precedenza si potrà far
ripartire l'array con il comando:
\begin{Example}
mdadm --assemble /dev/md0 /dev/hda1 /dev/hdc1
\end{Example}

Alternativamente si possono riavviare in un colpo solo tutti gli array che
sono stati creati utilizzando soltanto l'opzione \texttt{-{}-scan}; questa è
una opzione generica presente in diverse modalità che consente di determinare
automaticamente gli argomenti riguardanti la composizione di un array mancanti
sulla riga di comando, come i dispositivi che ne fan parte, il file di
dispositivo ad esso associato o gli UUID dello stesso. Pertanto se si vogliono
avviare tutti gli array creati in precedenza si potrà usare semplicemente il
comando:
\begin{Example}
mdadm --assemble --scan
\end{Example}

L'uso della sola opzione \texttt{-{}-scan} comporta una serie di operazioni
abbastanza complesse; come primo passo viene usato, se presente,
\texttt{mdadm.conf}, ed assemblati gli array ivi dichiarati con le direttive
\texttt{ARRAY}, altrimenti viene usato il contenuto di
\texttt{/proc/partitions} per identificare la presenza di dispositivi che
possono far parte di un array e se il nome della macchina a cui fanno
riferimento corrisponde a quello della direttiva \texttt{HOMEHOST} questi
vengono fatti partire automaticamente.

Infine siccome che non è detto che si voglia far partire sempre tutti gli
array presenti, ad esempio se si vogliono effettuare dei controlli sui singoli
componenti e non avviare un array, o farlo partire in modalità degradata, è
possibile avviare un singolo array utilizzando l'UUID che viene associato a
ciascun RAID quando questo viene creato. In tal caso si dovrà usare l'opzione
\texttt{-u} (o \texttt{-{}-uuid}) per specificare il valore dell'UUID e con
\texttt{-{}-scan} verranno identificati ed utilizzati automaticamente solo i
dispositivi ad esso corrispondenti.

Una volta assemblato un array con \texttt{-{}-assemble} questo in genere viene
anche avviato e reso disponibile, ma soltanto se si sono specificati negli
argomenti tutti i componenti che ne fanno parte o si è usato \texttt{-{}-scan}
che li inserisce automaticamente. Nel caso di RAID che supportano la
ridondanza è possibile anche far partire un array in \textsl{modalità
  degradata}, escludendo ad esempio, fintanto che gli altri sono sufficienti a
far funzionare l'array, alcuni dei suoi componenti; in tal caso però deve
essere specificata l'opzione \texttt{-{}-run}, altrimenti l'array sarà
assemblato, ma non avviato. 

Si tenga presente comunque che difficilmente, se non in caso di problemi,
capiterà di eseguire queste operazioni a mano; gli script di avvio usati da
tutte le distribuzioni infatti si incaricano usualmente di avviare
automaticamente tutti gli array di una macchina. Qualora però per un qualche
motivo detto avvio fallisse, cosa che può accadere se ad esempio i dischi che
ne fanno parte non sono stati ancora riconosciuti al momento in cui se ne
richiede l'avvio, si potrà far ripartire un array utilizzando \texttt{mdadm}
in questa modalità.

Nella gestione ordinaria, fintanto che non ci sono problemi, è assai raro
dover usare \texttt{mdadm}. La situazione cambia quando un componente di un
array fallisce, come nel caso di un disco che si rompe, per cui ci si troverà
in presenza di un array degradato e si dovranno prendere gli opportuni
provvedimenti. Il primo passo è accorgersi di queste situazioni e per questo
motivo \texttt{mdadm} prevede una apposita modalità \textit{Monitor}, che
normalmente viene attivata direttamente all'avvio dalla gran parte delle
distribuzioni. Ovviamente la modalità ha senso solo per i livelli che
supportano la ridondanza, in cui l'accesso ai dati continua a funzionare,
negli altri casi il fallimento diventa immediatamente evidente.

Se usato in questa modalità \texttt{mdadm} resta attivo e continua a
controllare lo stato degli array, registrando eventuali cambiamenti di stato
ed inviando gli allarmi via email all'amministratore. In genere il comando
viene fatto eseguire in \textit{background} come demone, usando l'opzione
\texttt{-f} (o \texttt{-{}-daemonise}), direttamente dagli script di avvio,
altrimenti resta attivo sulla console stampando i suoi messaggi sullo
\textit{standard output}. In questa modalità si può specificare la lista degli
array da tenere sotto controllo con i relativi file di dispositivo, ma al
solito l'opzione \texttt{-{}-scan} consente di mettere sotto controllo in un
colpo solo tutti quelli definiti in \texttt{mdadm.conf}.

Il programma rileva una serie di cambiamenti di stato, e genera altrettanti
eventi, che, usando l'opzione \texttt{-y} (o \texttt{-{}-syslog}), vengono
registrati sul sistema del \textit{syslog}. Inoltre per alcuni di questi
eventi, quelli che indicano una situazione problematica, come il fallimento di
un disco o il degrado di un array, è previsto l'invio automatico di una email
di avvertimento all'indirizzo specificato nella direttiva \texttt{MAILADDR} di
\texttt{mdadm.conf}, che può comunque essere soprasseduto con l'opzione
\texttt{-m} (o \texttt{-{}-mail}). Altre opzioni significative sono
\texttt{-d} (o \texttt{-{}-delay}), che consente di modificare l'intervallo di
tempo in cui vengono effettuati i controlli e \texttt{-l} (o
\texttt{-{}-oneshot}) che consente di eseguire un controllo singolo; al solito
per i dettagli, e per il significato e le priorità dei vari eventi, si
consulti la pagina di manuale.

Una volta che si sia stati notificati di un problema sugli array, occorrerà
provvedere alla sua soluzione; per far questo la modalità da usare è la
\textit{Manage}. Il caso classico è quello della rottura di un disco che dovrà
essere sostituito nel più breve tempo possibile; il primo passo è rimuovere il
disco rotto dall'array con l'opzione \texttt{-r} (o \texttt{-{}-remove}), dopo
di che si potrà spegnere la macchina (a meno di non avere dischi che
supportano un cambiamento a caldo) e sostituire il disco. Al riavvio il nuovo
disco potrà essere reinserito nell'array con \texttt{-a} (o
\texttt{-{}-add}). Si tenga presente che si possono rimuovere da un array
soltanto i dischi non in uso, vale a dire o dischi con errori che sono stati
marcati come \textit{fail} o dischi \textit{spare}.  È anche possibile, con
l'opzione \texttt{-f} (o \texttt{-{}-fail}), forzare il fallimento di un disco
funzionante, cosa che si può usare ad esempio qualora si voglia sostituire un
disco anche se non è fisicamente rotto.

In tutti questi casi \texttt{mdadm} richiede che si indichi sempre per primo
il file di dispositivo relativo all'array su cui si opera mentre i successivi
devono fare riferimento ai dischi che ne fanno parte; è possibile infatti
eseguire più operazioni su una sola riga di comando, anche se poco
consigliabile vista la scarsa leggibilità che si ottiene in tal modo. Se
allora nell'esempio di RAID 1 mostrato in precedenza fallisce il secondo disco
IDE, si potrà provvedere alla sua sostituzione dopo averlo rimosso con il
comando:
\begin{Example}
mdadm /dev/md0 --remove /dev/hdc1
\end{Example}
ed una volta sostituito si potrà inserire il nuovo disco nell'array,
(supponendo di non aver cambiato canale IDE), con:
\begin{Example}
mdadm /dev/md0 --add /dev/hdc1
\end{Example}

Delle ulteriori funzionalità avanzate di gestione degli array sono state
introdotte nello sviluppo del kernel 2.6 con la modalità \textit{Grow} che
consente di modificare le dimensioni degli array. Fino allora infatti tutto
quello che si poteva fare era aggiungere dischi \textit{spare}, operazione che
aumenta la ridondanza, ma non lo spazio disponibile. In modalità \textit{Grow}
diventa invece possibile far crescere lo spazio disponibile; ovviamente il
funzionamento dipende dal tipo di RAID che si sta utilizzando. 

Esistono due modi per aumentare le dimensioni di un array; nel caso di RAID
nei livelli 4, 5 o 6 si può aggiungere un disco a quelli presenti, richiedendo
che le informazioni vengano distribuite anche su di esso, così da aumentare lo
spazio disponibile, come sarebbe stato se si fosse creato l'array fin
dall'inizio inserendovi anche il disco aggiuntivo. La seconda modalità prevede
invece la sostituzione dei dischi componenti un array con dischi di dimensioni
maggiori, e può essere utilizzata anche con RAID di livello 1. Si tenga
presente che in entrambi i casi quello che cambierà al termine delle
operazioni di \textsl{crescita} sarà la dimensione del dispositivo RAID, non
del filesystem in esso contenuto, che andrà opportunamente ridimensionato con
i comandi che vedremo in sez.~\ref{sec:filesystem_resize}. 

Nel primo caso la procedura prevede che prima si effettui l'aggiunta del disco
e poi si richieda l'accrescimento dell'array specificandone il nuovo numero di
dischi. In sostanza per aggiungere un nuovo disco ad un RAID 5 già composto da
tre dischi, in modo da estenderne le dimensioni, si dovrà prima aggiungere il
disco all'array con un comando analogo al seguente:\footnote{facendo
  ovviamente riferimento agli opportuni file di dispositivo relativi al
  proprio array.}
\begin{Example}
mdadm /dev/md1 --add /dev/sdd1
\end{Example}
e poi utilizzare \texttt{mdadm} in modalità \textit{Grow} per accrescere
l'array indicandogli il nuovo numero di componenti, con qualcosa come:
\begin{Example}
mdadm --grow /dev/md1 --raid-devices=4 
\end{Example}

Si tenga presente che questo tipo di operazione richiede che i dati vengano
redistribuiti fra i vecchi ed il nuovo disco; questo procedimento è molto
oneroso e può durare parecchie ore (fino al limite delle intere giornate).
Inoltre all'inizio della procedura c'è un periodo critico in cui le
informazioni trasferite non possono essere salvate in maniera sicura
sull'array stesso. Per questo motivo, onde evitare che in caso di spegnimento
accidentale l'array si trovi in uno stato inconsistente (e probabilmente
irrecuperabile), è sempre opportuno usare l'opzione \texttt{-{}-backup-file} per
indicare un file su cui salvare dette informazioni, che ovviamente deve stare
su un dispositivo diverso dall'array stesso.

Qualora invece si voglia operare un accrescimento dell'array attraverso il
rimpiazzo dei suoi componenti con dischi di dimensione maggiore il primo passo
è effettuare la sostituzione successiva di ciascuno di essi; per far questo
prima occorre marcare un disco come difettoso con un comando analogo al
seguente:
\begin{Example}
mdadm /dev/md0 --fail /dev/hda1
\end{Example}
e poi rimuoverlo dal RAID con:
\begin{Example}
mdadm /dev/md0 --remove /dev/hda1
\end{Example}
a questo punto si potrà sostituire il disco come nel precedente caso di
rottura, utilizzandone un altro di dimensioni maggiori (che si sarà
opportunamente partizionato), per poi riaggiungerlo al RAID con:
\begin{Example}
mdadm /dev/md0 --add /dev/hda1
\end{Example}

Si dovrà poi ripetere l'operazione per tutti i dischi che compongono l'array,
aspettando dopo ogni sostituzione che l'array si risincronizzi. Una volta
fatto questo si avrà un array identico a quello di partenza, in cui però viene
usata solo una parte dello spazio disponibile sui dispositivi componenti, il
passo finale è quello di usare \texttt{mdadm} in modalità \textit{Grow} per
eseguire l'accrescimento dell'array usando l'opzione \texttt{-z} (o
\texttt{-{}-size}) per indicare la nuova dimensione con qualcosa del tipo:
\begin{Example}
mdadm --grow /dev/md0 --size=max
\end{Example}
dove \texttt{max} è una parola riservata che richiede che la dimensione
dell'intero array venga portata al massimo dello spazio utilizzabile nei
dischi che ne fan parte.

Si ricordi comunque che l'accrescimento di un array non comporta il
ridimensionamento del filesystem da esso contenuto. Inoltre si tenga presente
che le operazioni di accrescimento degli array non aggiornano automaticamente
il contenuto di \texttt{mdadm.conf}, che deve essere modificato manualmente
(questo in realtà deve essere fatto soltanto nel primo dei due casi trattati,
cambiando il numero dei componenti).

In questo possono essere di ausilio alcune delle funzionalità fornite da
\texttt{mdadm} in modalità \textit{Misc}, in particolare si può combinare
l'opzione \texttt{-D} (o \texttt{-{}-examine}) che usualmente richiede
l'indicazione del dispositivo di un array per stamparne caratteristiche e
componenti, con l'opzione \texttt{-{}-scan}, così da ottenere un risultato del
tipo:
\begin{Console}
gethen:~# \textbf{mdadm --examine --scan}
ARRAY /dev/md0 level=raid1 num-devices=2 UUID=79448936:36120176:1eaacd19:dfef9fa6
\end{Console}
che fornisce uno scheletro del contenuto di \texttt{mdadm.conf} a partire dal
contenuto degli array stessi.

Lo stesso risultato si ottiene anche con l'opzione \texttt{-E} (o
\texttt{-{}-query}) che invece, prendendo sempre come argomento un file di
dispositivo, permette di vedere se questo a seconda dei casi è un array o fa
parte di un array. Se ad essa si aggiungono le ulteriori opzioni
\texttt{-{}-detail} e \texttt{-{}-scan} si riotterrà il risultato precedente.

Altre opzioni significative della modalità \textit{Misc} sono \texttt{-S} (o
\texttt{-{}-stop}) che disattiva un array, che ovviamente non deve essere in
uso, \texttt{-o} (o \texttt{-{}-readonly}) che porta l'array in sola lettura,
e \texttt{-w} (o \texttt{-{}-readwrite}) che lo porta in lettura e
scrittura. Di nuovo per i dettagli si consulti la pagina di manuale di
\texttt{mdadm}.

Esistono infine una serie di opzioni generiche che si applicano a qualunque
modalità di operazione; a parte \texttt{-{}-scan} e \texttt{-{}-homehost} che
abbiamo già visto, la principale di queste è \texttt{-c} (o
\texttt{-{}-config}) che consente di indicare un file di configurazione
alternativo rispetto a \texttt{mdadm.conf}; inoltre passando a \texttt{-c} il
valore \texttt{partitions} si indica a \texttt{mdadm} di ignorare un eventuale
contenuto del file di configurazione, con un comportamento equivalente a
quello di avere la sola riga \texttt{DEVICE partitions} in
\texttt{mdadm.conf}.  Altre due opzioni generiche sono \texttt{-v} che aumenta
la prolissità del comando e \texttt{-q} che la riduce.

\section{Il sistema del \textit{Logical Volume Manager}}
\label{sec:disk_LVM} 

\itindbeg{Logical~Volume~Manager (LVM)}

Tratteremo in questa sezione il sistema del \textit{Logical Volume Manager},
uno speciale supporto nel kernel che permette di organizzare in maniera
flessibile lo spazio disco per superare le difficoltà di modificare le
dimensioni di una partizione qualora il filesystem in essa contenuto non abbia
più spazio sufficiente. L'uso del \textit{Logical Volume Manager} permette
cioè di evitare alla radice tutta le problematiche, evidenziate in
sez.~\ref{sec:partitioning}, relative alle diverse possibili strategie di
partizionamento.


\subsection{Introduzione}
\label{sec:LVM_intro}

Uno dei problemi che la struttura di un filesystem unix-like presenta è che
quando si riempie un dispositivo montato su una directory non se ne può
aumentare la dimensione direttamente semplicemente aggiungendo un altro disco
perché questo andrebbe montato altrove. Pertanto in casi come questi si è
spesso costretti a complesse operazioni di backup per sostituire il disco
riempitosi o a creare link simbolici spostando su altri dischi il contenuto di
alcune delle directory di quello troppo pieno.

Per superare alla radice questo problema è stato creato il sistema del
\textit{Logical Volume Manager}, grazie al quale è possibile creare un
filesystem invece che su un disco singolo o su una partizione, all'interno di
un ``\textsl{volume logico}''. Quest'ultimo poi non è altro che un dispositivo
virtuale creato a partire da un insieme di \textsl{volumi fisici}, che vengono
opportunamente \textsl{riuniti} dal kernel in modo da presentarsi come un
unico disco.

Il vantaggio è che i volumi logici possono essere ridimensionati a piacere
senza necessità di toccare le partizioni o i dischi che stanno al di sotto,
per cui usando i programmi per il ridimensionamento dei filesystem si possono
allargare o restringere questi ultimi in maniera molto comoda, e con certi
filesystem alcune operazioni possono essere eseguite a ``\textsl{caldo}'', con
il filesystem montato. In questo modo se lo spazio disco su un volume logico
si esaurisce basterà allargarlo, e se lo spazio disco sottostante non è
sufficiente basterà comprare un nuovo disco ed agganciarlo al volume logico,
per espanderne le dimensioni senza doversi preoccupare di ripartizionare,
montare, fare link e spostare contenuti da un disco ad un altro.

Lo schema del funzionamento del \textit{Logical Volume Manager} (da qui in
breve LVM) è riportato in fig.~\ref{fig:adv_LVM_struct}. Il sistema consiste
nell'introdurre un livello intermedio, quello del \textsl{gruppo di volumi}
(indicato in figura con la notazione \textsf{VG}, da \textit{volume group}),
che viene a costituire l'interfaccia fra i volumi logici (indicati con
\textsf{LV} da \textit{logical volume}), che da esso si estraggono, ed i
volumi fisici (indicati con \textsf{PV}, da \textit{physical volume}), che lo
vanno a costituire. In sostanza il kernel si cura di suddividere un disco
fisico in tante piccole sezioni (dette \textit{physical extent}, e indicate in
figura con \textsf{PE}) che poi vengono rimappate\footnote{da cui il nome di
  \textit{device mapper} che il sistema ha assunto a partire dal kernel 2.6.x,
  dove è stato riscritto da zero per migliorare stabilità e prestazioni.} nei
corrispondenti \textit{logical extent} (indicati con \textsf{LE}) che vanno a
costituire un volume logico.

\begin{figure}[htb]
  \centering
  \includegraphics[width=11cm]{images/lvm_struct}
  \caption{Strutturazione del \textit{Logical Volume Manager}.}
  \label{fig:adv_LVM_struct}
\end{figure}

Una delle funzionalità più interessanti di LVM è quella di poter utilizzare il
sistema per poter creare degli \textit{snapshot}, cioè poter creare una copia
dello stato di un volume logico ad un certo istante utilizzando lo spazio
libero nel \textsl{gruppo di volumi} di cui questo fa parte. Tutto ciò viene
realizzato allocando dello spazio libero per contenere tutte le modifiche
eseguite al volume originario.  La versione corrente del filesystem sul volume
logico originale registrerà tutte le modifiche nel nuovo spazio allocato,
mentre il volume creato come \textit{snapshot} conterrà i dati così come erano
al momento della creazione.

Questo è molto comodo per poter eseguire dei backup per volumi di grosse
dimensioni senza doversi preoccupare del fatto che durante l'esecuzione del
backup i dati vengano modificati; basta assicurarsi che nel breve tempo
necessario a creare lo \textit{snapshot} non ci siano attività, dopo di che si
potrà eseguire il backup con tutta calma su di esso mentre le operazioni
continuano regolarmente sul volume originale. Una volta completato il backup
si potrà rimuovere il volume logico usato per lo \textit{snapshot} ed il
volume logico originario manterrà in maniera trasparente tutte le modifiche
eseguite nel frattempo; l'unico aspetto critico è quello di assicurarsi di
avere allocato per lo \textit{snapshot} spazio sufficiente a contenere tutte
le modifiche, se infatti questo dovesse esaurirsi il volume logico originale
diverrebbe inusabile.

Per poter utilizzare LVM occorre abilitare il relativo supporto nel kernel
(vedi sez.~\ref{sec:kernel_compile}), ed avere installato gli opportuni
programmi in \textit{user-space}. Nel passaggio dal kernel 2.4.x al 2.6.x il
sistema è stato completamente riscritto, pertanto si potranno avere delle
differenze a seconda che si usi la prima versione (detta anche LVM1) o la
seconda (detta LVM2). In ogni caso la nuova versione è in grado di riconoscere
la presenza di volumi logici creati con la versione precedente (ormai in
completo disuso) e di riutilizzarli senza problemi, ed ha in genere
prestazioni nettamente superiori.


\subsection{La gestione dei \textsl{volumi fisici}}
\label{sec:adv_LVM_phys_vol}

Il primo passo nell'uso di LVM è quello della inizializzazione dei volumi
fisici; per questi può essere usato un qualunque dispositivo a
blocchi. L'elenco dei dispositivi accettati può essere limitato con la
direttiva \texttt{filter} nel file di configurazione
\index{configurazione!\texttt{/etc/lvm/lvm.conf}} \texttt{/etc/lvm/lvm.conf},
che non prevede alcuna esclusione. Il caso più comune è quello dell'uso di una
partizione di un disco, che è opportuno marcare (vedi
sez.~\ref{sec:partitioning}) con il codice \texttt{0x8E} per indicare che
verrà utilizzata come volume fisico per LVM. Una scelta altrettanto comune è
quella di usare un dispositivo RAID software (nel qual caso non serve nessun
altro accorgimento).

Ogni dispositivo che si intende usare come volume fisico deve essere
inizializzato con il comando \index{comando!\texttt{pvcreate}}
\texttt{pvcreate} così come si farebbe per un filesystem; il comando prende
come argomento il file di dispositivo che identifica il volume fisico sul
quale creare l'infrastruttura per mantenere le informazioni relative a LVM, e
se ne possono specificare anche più di uno per una inizializzazione
multipla. A meno di non impostare una dimensione inferiore con l'opzione
\texttt{-{}-setphysicalvolumesize} il volume occuperà l'intero spazio
disponibile sul dispositivo.

Oltre che ad una partizione il comando \texttt{pvcreate} può essere applicato
anche ad un intero disco, nel qual caso però occorre prima cancellare la
tabella delle partizioni, perché se questa viene rilevata il comando segnala
un errore. Questo si può fare facilmente con un comando di cancellazione come:
\begin{Example}
dd if=/dev/zero of=/dev/hdX bs=512 count=1
\end{Example}

Il comando prende come opzioni specifiche \texttt{-u}, che permette di
specificare uno UUID a mano invece di farlo generare automaticamente, e
\texttt{-f} che forza la creazione del volume senza richiedere conferma,
distruggendo all'instante eventuali dati presenti. Le altre opzioni riguardano
aspetti specifici della gestione interna ed al solito rimandiamo alla pagina
di manuale, ma in genere non c'è bisogno di usare niente altro che il comando
applicato al dispositivo, ad esempio con un comando del tipo:
\begin{Console}
hain:~# \textbf{pvcreate /dev/sdb1}
  Physical volume "/dev/sdb1" successfully created
\end{Console}
si inizializzerà la prima partizione del secondo disco SCSI come volume fisico
per LVM.

Con il comando \index{comando!\texttt{pvscan}} \texttt{pvscan}, si può
eseguire una scansione dei dischi presenti per rilevare al loro interno la
presenza di volumi fisici usati da LVM, il comando si invoca senza argomenti,
e si avrà un risultato del tipo:
\begin{Console}
anarres:~# \textbf{pvscan} 
  PV /dev/sda3   VG vg   lvm2 [132.23 GB / 85.73 GB free]
  PV /dev/md0    VG vg   lvm2 [931.00 GB / 737.57 GB free]
  Total: 2 [1.04 TB] / in use: 2 [1.04 TB] / in no VG: 0 [0   ]
\end{Console}
che mostra la presenza di due volumi fisici associati ad un gruppo di volumi e
parzialmente utilizzati.

Le opzioni del comando controllano sostanzialmente l'informazione che viene
stampata a video, con \texttt{-s} si riduce la stessa al minimo, con
\texttt{-u} si fanno stampare gli UUID presenti, con \texttt{-n} si stampano
solo i volumi fisici che non appartengono ad un volume logico, per le altre
opzioni si faccia riferimento alla pagina di manuale.

Un secondo comando diagnostico è \index{comando!\texttt{pvdisplay}}
\texttt{pvdisplay} che stampa a video le caratteristiche di uno o più volumi
fisici, specificati come argomenti. Se non si specifica nulla il comando
stampa i dati relativi a tutti i volumi fisici presenti, altrimenti se ne può
indicare uno (o più) passando come argomenti i relativi file di dispositivo;
nel nostro caso visto che abbiamo appena creato un volume fisico su
\texttt{/dev/sdb1} potremo controllarne le caratteristiche con:
\begin{Console}
monk:~# \textbf{pvdisplay /dev/sdb1}
  "/dev/sdb1" is a new physical volume of "1,91 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/sdb1
  VG Name               
  PV Size               1,91 GiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               DqBTm8-F9Tk-Eczy-4Slb-RTwl-8Vs0-54j61P
\end{Console}
mentre nel caso lo si usi su una macchina in cui è presente un volume fisico
in uso, avremo invece qualcosa del tipo:
\begin{Console}
hain:~# \textbf{pvdisplay} 
  --- Physical volume ---
  PV Name               /dev/md2
  VG Name               vg
  PV Size               462,96 GB / not usable 2,31 MB
  Allocatable           yes 
  PE Size (KByte)       4096
  Total PE              118518
  Free PE               10763
  Allocated PE          107755
  PV UUID               VO7DXX-4hMk-CDuE-PykW-y8bF-q7h0-pWCtHo
\end{Console}

Anche per questo comando le opzioni servono a controllare l'informazione
riportata; le principali sono \texttt{-s}, che fa stampare solo la dimensione
totale del volume e \texttt{-c} che produce un output compatto in cui i vari
dati relativi al volume sono separati da un carattere ``\texttt{:}'' così da
poterlo usare facilmente per fare scansioni sulle loro proprietà all'interno
di script. A queste si aggiunge l'opzione \texttt{-m} che consente di ottenere
una mappa completa delle corrispondenze nelle allocazioni fra \textit{physical
  extent} e \textit{logical extent} indicando anche i volumi logici i cui dati
sono presenti sul volume fisico, utile per capire le allocazioni quando si
devono spostare i dati fra volumi fisici con \texttt{pvmove}. Al solito per
tutti i dettagli si può fare riferimento alla pagina di manuale.

Un comando alternativo a \texttt{pvdisplay}, disponibile a partire dalla
versione 2 di LVM, è \texttt{pvs}, che consente un controllo molto più
dettagliato della stampa in colonne dei dati. Se invocato senza argomenti il
comando stampa un riassunto in forma tabellare dei dati dei dischi, ad
esempio:
\begin{Console}
anarres:~# \textbf{pvs} 
  PV         VG   Fmt  Attr PSize   PFree  
  /dev/md0   vg   lvm2 a-   931.00G 737.57G
  /dev/sda3  vg   lvm2 a-   132.23G  85.73G
\end{Console}

Il comando al solito supporta l'indicazione dei dispositivi da analizzare, da
passare come argomenti. Ma la vera potenza del comando è la possibilità di
adattare la stampa delle informazioni sulla base dei parametri passati
all'opzione \texttt{-o}, che consentono di ottenere i dettagli sulle
allocazioni dei \textit{physical extent} ed i volumi logici cui questi sono
associati; per i dettagli si rimanda di nuovo alla pagina di manuale.

Qualora si cambino le dimensioni di una partizione o di un dispositivo (ad
esempio un RAID) che contiene un volume fisico, è possibile modificare anche
le dimensioni di quest'ultimo con il comando \index{comando!\texttt{pvresize}}
\texttt{pvresize}, che prende come argomenti una lista di dispositivi su cui
si sono installati dei volumi fisici. Il comando può operare su volumi fisici
che sono già parte di un gruppo di volumi e che ospitano dati relativi a
volumi logici; se dato senza opzioni i volumi fisici vengono ridimensionati
automaticamente alla dimensione corrente del dispositivo sottostante.

Qualora sia necessario ridurre la dimensione di un volume fisico (ad esempio
se è necessario restringere una partizione) si deve invece usare la speciale
opzione \texttt{-{}-setphysicalvolumesize} che richiede come parametro
l'indicazione della dimensione da dare al volume fisico. Ovviamente qualora si
debba ridurre la dimensione di una partizione su cui è presente un volume
fisico è necessario eseguire prima questa operazione.

Infine un comando estremamente utile è \index{comando!\texttt{pvmove}}
\texttt{pvmove} che permette di spostare tutti i dati mantenuti su un certo
volume fisico su di un altro, così da poterlo rimuovere dal gruppo di volumi
di cui fa parte.  Il comando prende come argomenti il volume fisico sorgente
da cui rimuovere i dati e quello di destinazione su cui inviarli; ovviamente
la destinazione deve avere spazio libero sufficiente a contenerli. Si può
anche evitare di specificare un volume fisico di destinazione, nel qual caso
lo spazio sarà redistribuito automaticamente sui volumi appartenenti allo
stesso gruppo.

Il comando ha tre opzioni principali, la prima è \texttt{-i} che fa stampare
una percentuale di completamento delle operazioni tutte le volte che è
trascorso il numero di secondi passato come parametro; con \texttt{-n} invece
si può restringere lo spostamento ai dati relativi al solo volume logico il
cui nome si è passato come parametro. Infine con \texttt{-{}-abort} si può
abortire un precedente tentativo di spostamento non completato; se infatti il
comando viene interrotto durante l'esecuzione non c'è nessun problema, e
basterà reinvocarlo senza parametri per fare ripartire lo spostamento dal
punto un cui era stato interrotto, a meno appunto di invocare \texttt{pvmove
  -{}-abort}.



\subsection{La gestione dei \textsl{gruppi di volumi}}
\label{sec:adv_LVM_volume_group}

Una volta inizializzati tutti i volumi fisici necessari il secondo passo è
combinarli in un \textsl{gruppo di volumi}, per questo si deve usare il
comando \index{comando!\texttt{vgcreate}} \texttt{vgcreate} che crea un nuovo
gruppo di volumi assegnandogli il nome specificato come primo argomento, ed
inserendoci tutti i volumi fisici specificati negli argomenti successivi.
Perché il comando abbia successo tutti i volumi fisici devono essere stati
preventivamente inizializzati con \texttt{pvcreate}.  Una volta creato un
gruppo di volumi con nome \texttt{vgname} si avrà a disposizione una
corrispondente directory \texttt{/dev/vgname/} in cui si troveranno tutti i
file (in particolare i file relativi ai volumi logici, che tratteremo in
sez.~\ref{sec:adv_LVM_logical_volume}).

L'opzione \texttt{-s} permette di definire le dimensioni dei \textit{physical
  extent} in cui saranno divisi i volumi fisici, da passare come argomento
numerico seguito dalle estensioni standard per indicare kilo, mega e gigabyte.
La dimensione standard è di 4Mb, ed i valori possono spaziare da 4kb a 16Gb in
potenze di due, si tenga presente che con la vecchia versione di LVM1 un
volume logico può mantenere un massimo di 64k \textit{physical extent} che
comporta una dimensione massima di 256Gb, la nuova versione non ha un limite,
ma un numero eccessivo di \textit{physical extent} tende a peggiorare
notevolmente le prestazioni, pertanto se si ha a disposizione molto spazio
disco conviene usare delle dimensioni più ampie per i \textit{physical
  extent}.

L'opzione \texttt{-l} permette di definire un numero massimo di volumi logici
che possono essere estratti dal gruppo; il valore massimo assoluto era di 255
con LVM1, con LVM2 questa restrizione non sussiste più ed il default è 0 che
indica che non c'è nessun limite. Con \texttt{-p} invece si imposta il numero
massimo di volumi fisici che possono essere inclusi, ed anche in questo caso
si aveva un massimo di 255 per LVM1 e nessun limite per LVM2. Con \texttt{-u}
si può impostare manualmente un UUID. Per le ulteriori opzioni si può fare
riferimento alla pagina di manuale, un elenco di opzioni comuni a buona parte
dei comandi che operano con i gruppi ed i volumi logici si trova in
tab.~\ref{tab:adv_LVM_common_options}, l'elenco completo invece è riportato
nella pagina di manuale dedicata a LVM, accessibile con \texttt{man lvm}, ma
normalmente sarà sufficiente un comando come:
\begin{Console}
monk:~# \textbf{vgcreate vg /dev/hda3}
  Volume group "vg" successfully created
\end{Console}
che crea il nuovo gruppo di volumi \texttt{vg} con il volume fisico
\texttt{/dev/hda3} precedentemente inizializzato.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-v} & imposta il livello di prolissità, può essere ripetuto fino a
                  tre volte per aumentare le informazioni stampate a video. \\
    \texttt{-d} & importa il livello di debug, può essere ripetuto fino a sei 
                  volte per aumentare le informazioni stampate a video.\\
    \texttt{-t} & esegue il comando in modalità di test, i dati non vengono
                  modificati. \\
    \texttt{-h} & stampa un messaggio di aiuto. \\
    \texttt{-M} & imposta il formato dei meta-dati, prende come valore
                  \texttt{lvm1} o \texttt{lvm2} (o semplicemente il numero),
                  questa opzione è disponibile solo su LVM2.\\
    \texttt{-A} & esegue automaticamente il backup dei meta-dati quando essi
                  vengono cambiati, prende come valore \texttt{y} o
                  \texttt{n}, (il default è il primo e non è il caso di
                  cambiarlo).\\
    \hline
  \end{tabular}
  \caption{Principali opzioni comuni dei comandi di gestione di LVM.}
  \label{tab:adv_LVM_common_options}
\end{table}

Una volta creato un gruppo di volumi questo può essere espanso aggiungendovi
altri volumi fisici con \index{comando!\texttt{vgextend}} \texttt{vgextend},
che di nuovo prende come primo argomento il nome del gruppo, che stavolta deve
esistere, seguito dai volumi fisici che si vogliono aggiungere, al solito
specificati tramite il relativo file di dispositivo. Per i dettagli sulle
opzioni (alcune delle quali sono riportate in
tab.~\ref{tab:adv_LVM_common_options}) si può fare riferimento alla pagina di
manuale.

Il lavoro opposto, quello di rimuovere un volume da un gruppo, viene invece
eseguito da \index{comando!\texttt{vgreduce}} \texttt{vgreduce} che al solito
prende come primo argomento il nome del gruppo, seguito dai volumi che si
vogliono rimuovere. Ovviamente perché il comando abbia successo tutti i volumi
che si vogliono rimuovere dal gruppo non devono essere utilizzati; con
l'opzione \texttt{-a} non è necessario specificare quali volumi rimuovere,
dato che in tal caso si rimuoveranno tutti quelli non utilizzati. Al solito
per i dettagli sul comando e le altre opzioni supportate si faccia riferimento
alla pagina di manuale.

La creazione di un gruppo di volumi è comunque solo un primo passo, prima di
poterlo utilizzare infatti questo deve essere \textsl{attivato} in modo da
poter essere utilizzato. Per questo si usa in genere il comando
\index{comando!\texttt{vgchange}} \texttt{vgchange} il cui scopo è quello di
modificare le proprietà di un gruppo di volumi. Il comando al solito prende
come argomento il nome del gruppo di volumi, ma se non se ne specifica uno si
applica a tutti quelli presenti.

L'opzione principale è \texttt{-a} che è quella che permette di attivare o
disattivare il gruppo, rispettivamente con i parametri ``\texttt{y}'' e
``\texttt{n}''; in genere gli script di avvio di LVM eseguono sempre un
comando del tipo \texttt{vgchange -a y}. Le altre opzioni sono utilizzate
principalmente per cambiare le caratteristiche del gruppo di volumi rispetto
ai valori impostati in fase di creazione: \texttt{-l} modifica il numero
massimo di volumi logici, passato come parametro (deve essere eseguita su un
gruppo inattivo), \texttt{-x} attiva o disattiva (sempre con i parametri
``\texttt{y}'' e ``\texttt{n}'') la possibilità di estendere o ridurre il
gruppo togliendo o aggiungendo volumi fisici, \texttt{-u} consente di
modificare l'UUID associato al gruppo di volumi.

Un secondo comando usato all'avvio del sistema, ma solo per LVM1, in LVM2 la
cosa è automatica, è \index{comando!\texttt{vgscan}} \texttt{vgscan} che
esegue una scansione dei dischi presenti per rilevare la presenza di gruppi di
volumi (analogo a quanto fa \texttt{pvscan} per i volumi fisici), in genere lo
si lancia prima di \texttt{vgchange}, e l'unica opzione significativa (per le
altre si consulti la pagina di manuale) è \texttt{-{}-mknodes} che crea in
\texttt{/dev} i file speciali necessari all'uso dei dispositivi. Un esempio è:
\begin{Console}
monk:~# \textbf{vgscan}
  Reading all physical volumes.  This may take a while...
  Found volume group "vg" using metadata type lvm2
\end{Console}

Esiste poi un comando analogo di \texttt{pvdisplay} da usare per i gruppi di
volumi; con \index{comando!\texttt{vgdisplay}} \texttt{vgdisplay} si possono
elencare le caratteristiche del gruppo passato come argomento, o di tutti
quelli presenti nel sistema se non si specifica nulla. Le opzioni sono le
stesse già viste in sez.~\ref{sec:adv_LVM_phys_vol} per \texttt{pvdisplay}; un
esempio di questo comando è:
\begin{Console}
monk:~# \textbf{vgdisplay}
--- Volume group ---
  VG Name               vg
  System ID             
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               185,38 GB
  PE Size               4,00 MB
  Total PE              47457
  Alloc PE / Size       0 / 0   
  Free  PE / Size       47457 / 185,38 GB
  VG UUID               njlk5d-xvsQ-pXcI-sEnK-zqII-YzzN-pNoI0Y
\end{Console}

Quando si vogliono riunire in uno solo due gruppi di volumi si può utilizzare
il comando \index{comando!\texttt{vgmerge}} \texttt{vgmerge}, questo prende
come primo argomento il gruppo di destinazione, che diventerà l'unione dei
due, e come secondo il gruppo da inglobare nel primo, che deve essere
disattivo. Il comando funziona soltanto se i due volumi sono stati creati con
parametri compatibili (stessa versione dei meta-dati e stessa dimensione dei
\textit{physical extent}) e se l'unione dei due rispetta i limiti presenti sul
gruppo di destinazione. Per le opzioni (che sono sostanzialmente quelle comuni
di tab.~\ref{tab:adv_LVM_common_options}) e per gli altri dettagli si faccia
riferimento alla pagina di manuale.

Se invece si vuole spezzare in due un gruppo di volumi si può usare il comando
\index{comando!\texttt{vgsplit}} \texttt{vgsplit}, questo prende come primo
argomento il nome del gruppo da cui si parte e come secondo quello del nuovo
gruppo che si vuole creare, seguito dalla lista dei volumi fisici da inserire
in quest'ultimo. Dato che i volumi logici non possono essere suddivisi fra
gruppi diversi occorrerà che ciascun volume logico esistente sia compreso
interamente nei volumi fisici che restano in uno dei due gruppi. Al solito per
le opzioni (sono solo quelle comuni) ed i dettagli si può fare riferimento
alla pagina di manuale.



\subsection{La gestione dei \textsl{volumi logici}}
\label{sec:adv_LVM_logical_volume}

Una volta creato un \textsl{gruppo di volumi} sarà possibile estrarre da esso
lo spazio necessario a creare un \textsl{volume logico}. Il comando principale
per eseguire questo compito è \index{comando!\texttt{lvcreate}}
\texttt{lvcreate} che crea il volume logico allocando i \textit{logical
  extent} necessari dalla riserva di \textit{physical extent} disponibili.

Il comando richiede come argomento obbligatorio il nome del gruppo di volumi
da utilizzare, inoltre deve essere sempre specificata la dimensione del volume
logico che si va a creare; questo può essere fatto in due modi, o con
l'opzione \texttt{-l}, seguita dal numero di \textit{logical extent} da
utilizzare,\footnote{le dimensioni sono le stesse dei \textit{physical extent}
  sottostanti, definite in fase di creazione del gruppo.} o con l'opzione
\texttt{-L} seguita dalla dimensione in byte; l'opzione supporta anche la
specificazione di altre unità di misura come kilobyte, megabyte, gigabyte o
terabyte se si aggiunge al numero passato come parametro l'iniziale (va bene
sia maiuscola che minuscola) della misura utilizzata.

\itindbeg{device~mapper} 

Se non si specifica altro il comando crea un volume logico con un nome
assegnato automaticamente al valore \texttt{lvolN} dove \texttt{N} è il numero
progressivo usato internamente dal sistema; si può però specificare un nome
qualunque con l'opzione \texttt{-n lvname}; in questo caso si potrà accedere
al nuovo volume logico usando come file di dispositivo
\texttt{/dev/vgname/lvname}. Nei kernel della serie 2.6, dato che LVM è stato
riscritto appoggiandosi direttamente al sistema del \textit{device mapper} che
si cura di effettuare la mappatura fra \textit{physical extent} e
\textit{logical extent}, si potranno trovare i volumi logici anche
direttamente sotto la directory \texttt{/dev/mapper}, accessibili direttamente
con un nome del tipo \texttt{vgname-lvname}. Un esempio dell'uso più comune di
questo comando è il seguente:
\begin{Console}
monk:~# \textbf{lvcreate -L 50G -n data vg}
  Logical volume "data" created
\end{Console}

\itindend{device~mapper} 

Una delle funzionalità di LVM è che permette di suddividere i dati su più
volumi fisici in maniera analoga al RAID-0, definendo con l'opzione
\texttt{-i} un numero di \textit{stripes} su cui distribuire i dati.  Valgono
in questo caso le stesse considerazioni viste in sez.~\ref{sec:RAID_intro} per
il RAID-0, in particolare si avrà un enorme degrado di prestazioni qualora si
usassero partizioni diverse dello stesso disco come volumi fisici su cui
distribuire le \textit{stripes}. Se si utilizza questa funzionalità si può
anche specificare la dimensione delle \textit{stripes} con l'opzione
\texttt{-I}.

Se invece di un normale volume logico si vuole creare uno \textit{snapshot}
occorre invocare il comando con una modalità completamente diversa. In tal
caso infatti si deve usare l'opzione \texttt{-s} e specificare un nome con
l'opzione \texttt{-n}; inoltre gli argomenti obbligatori diventano due: il
nome del volume logico da usare come \textit{snapshot} e quello del volume
logico cui fare da \textit{snapshot}. Un elenco delle opzioni principali di
\texttt{lvcreate} è riportato in tab.~\ref{tab:adv_LVM_lvcreate}, il comando
utilizza anche molte delle opzioni generali accennate in
tab.~\ref{tab:adv_LVM_common_options}; per i dettagli al solito si può fare
riferimento alla pagina di manuale.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-i} & indica di utilizzare il numero di \textit{stripe} passato
                  come parametro per distribuire i dati sui volumi fisici
                  sottostanti.\\ 
    \texttt{-I} & imposta la dimensione di una \textit{stripe} nella
                  distribuzione dei dati su più volumi fisici (da specificare
                  con un numero \texttt{n} da 2 a 9 per indicare $2^\mathtt{n}$
                  kilobyte).\\
    \texttt{-l} & imposta la dimensione di un volume logico per numero
                  (passato come parametro) di \textit{logical extent}.\\
    \texttt{-L} & imposta la dimensione di un volume logico specificata in
                  byte, kilobyte, megabyte, gigabyte o terabyte. \\
    \texttt{-n} & imposta il nome del volume logico, passato come parametro.\\
    \texttt{-p} & importa i permessi sul volume logico, prende il valore
                  \texttt{r} per indicare sola lettura o \texttt{rw} per
                  indicare lettura e scrittura.\\
    % \texttt{-r} & importa il numero di settori da leggere in anticipo per
    %               migliorare le prestazioni (solo per LVM1).\\
    \texttt{-s} & indica la richiesta di creazione di un volume di
                  \textit{snapshot}.  \\
    \hline
  \end{tabular}
  \caption{Principali opzioni del comando \texttt{lvcreate}.}
  \label{tab:adv_LVM_lvcreate}
\end{table}

Come per i volumi fisici ed i gruppi di volumi sono presenti due comandi,
\index{comando!\texttt{lvscan}} \texttt{lvscan} e
\index{comando!\texttt{lvdisplay}} \texttt{lvdisplay}, che possono essere
usati rispettivamente per eseguire una scansione dei volumi logici presenti e
per ottenere un sommario delle relative proprietà. Anche le opzioni sono
analoghe e non staremo a ripeterle.

La comodità di LVM consiste nel fatto che una volta che si è creato un volume
logico si potrà accedere a quest'ultimo con il relativo file di dispositivo e
trattarlo come un qualunque disco; il vantaggio è che qualora si avesse la
necessità di ampliarne le dimensioni si potrà ricorrere al comando
\index{comando!\texttt{lvextend}} \texttt{lvextend}, dopo di che non resterà
che ridimensionare il filesystem presente sul volume logico (vedi
sez.~\ref{sec:filesystem_resize}) per avere a disposizione lo spazio
aggiunto.

Il comando richiede obbligatoriamente come argomento il volume da estendere e
la dimensione finale dello stesso che deve essere specificata o con l'opzione
\texttt{-l} in numero di \textit{logical extent} o direttamente con l'opzione
\texttt{-L} (con la stessa convenzione di \texttt{lvcreate}). Si possono però
usare le stesse opzioni per specificare la dimensione dell'estensione al posto
di quella totale, apponendo al valore specificato il carattere ``\texttt{+}''.

Il comando supporta anche l'uso delle \textit{stripe} (con le stesse opzioni
di tab.~\ref{tab:adv_LVM_lvcreate}) ed inoltre si può specificare come
argomenti ulteriori una lista di volumi fisici sui quali si vuole che sia
compiuta l'estensione del volume logico. Il comando permette anche di
estendere le dimensioni dei volumi di \textit{snapshot}.

Se invece di aumentare le dimensioni di un volume logico le si vogliono
ridurre si deve usare \index{comando!\texttt{lvreduce}} \texttt{lvreduce}. Il
comando prende gli stessi argomenti ed opzioni di \texttt{lvextend} (esclusi
quelli relativi alle \textit{stripe}), solo che in questo caso la dimensione
può essere specificata apponendovi un segno ``\texttt{-}'' per richiedere una
riduzione.  Si tenga presente che i dati presenti nella parte tolta con la
riduzione vengono persi, pertanto è fondamentale ridurre le dimensioni di un
eventuale filesystem presente sul volume logico \textsl{prima} di eseguirne
una riduzione.

Per completare i comandi di ridimensionamento si deve citare il generico
\index{comando!\texttt{lvresize}} \texttt{lvresize} che unisce le funzionalità
dei precedenti \texttt{lvreduce} e \texttt{lvextend} permettendo
ridimensionamenti in qualunque direzione (sia crescenti che decrescenti). Di
nuovo le opzioni sono le stesse, e stavolta sono permessi per le dimensioni
sia il segno ``\texttt{+}'' che quello ``\texttt{-}''.

Qualora un volume logico non sia più utilizzato lo si può eliminare usando
\index{comando!\texttt{lvremove}} \texttt{lvremove}, il comando prende come
argomento uno o più volumi da rimuovere, l'unica opzione specifica supportata
è \texttt{-f} che permette di sopprimere la richiesta di conferma della
rimozione dallo \textit{standard input}.

<<<<<<< .mine

%\section{Il \textit{thin provisioning} su LVM}
% TODO da scrivere 

\itindend{Logical~Volume~Manager (LVM)}



\section{Gestione avanzata di dischi e filesystem}
\label{sec:adv_disk_filesystem}

Si sono raccolti in questa sezione una serie di argomenti avanzati riguardo la
gestione dei dischi e dei filesystem, come l'impostazione dei parametri di
basso livello dei dischi, % l'uso di partizioni cifrate, 
il ridimensionamento di filesystem e partizioni.

\subsection{La gestione dei parametri dei dischi}
\label{sec:hdparm_sdparm}

Finora abbiamo sempre trattato la gestione dei dischi facendo riferimento alle
operazioni da eseguire sui dati in essi contenuti all'interno di filesystem e
partizioni; non abbiamo trattato affatto le operazioni di basso livello con
cui il sistema può andare a modificare le caratteristiche e le modalità con
cui si accede ai dischi, effettuate direttamente attraverso l'interfaccia con
l'hardware degli stessi.

Tradizionalmente il programma per eseguire operazioni di basso livello sui
dischi è \index{comando!\texttt{hdparm}} \texttt{hdparm}, nato per impostare
le proprietà dell'accesso ai dischi e le loro modalità di funzionamento
attraverso l'interfaccia IDE/ATA, che a lungo è stata l'interfaccia
predominante per l'uso dei dischi su Linux, quando i dischi SCSI, per costo e
complessità, erano usati soltanto da una piccola percentuale di utenti. Il
comando comunque è in grado di funzionare con le nuove interfacce
\textit{serial ATA} supportate tramite il sistema di \textit{libata} del
kernel e sui dischi USB che supportano la traduzione dei comandi ATA su SCSI
(il cosiddetto SAT, \textit{SCSI-ATA Command Translation}).

Il comando prende come argomento il file di dispositivo del disco (o altro
dispositivo IDE) su cui si vuole operare, e se non si specifica altro stampa i
valori di una serie di parametri relativi al dispositivo stesso (l'esecuzione
senza opzioni è equivalente all'esecuzione con le opzioni \texttt{-acdgkmur})
più o meno completa a seconda della presenza o meno degli stessi o della
capacità di accedere alla relativa informazione. Il comando prevede una lunga
serie di opzioni di varia natura che consentono di effettuare impostazioni
sulle funzionalità dei dischi o del bus o di ottenere informazioni dettagliate
sugli stessi.

Un sottoinsieme di queste opzioni possono essere utilizzate sia per ottenere
che per modificare le impostazioni correnti, a seconda che si specifichi
soltanto l'opzione, nel qual caso il valore corrente sarà letto e stampato, o
ad essa si faccia seguire un valore numerico, il cui valore dipendente dalla
singola funzionalità, verrà usato come nuova impostazione.

Ad esempio con l'opzione \texttt{-a} è possibile modificare il numero di
settori in \textit{read ahead}, cioè letti in anticipo dal filesystem rispetto
a quelli indicati da una operazione di lettura; in questo modo è possibile
migliorare le prestazioni per la lettura di file di grandi dimensioni,
eseguendo una \textsl{lettura preventiva} del contenuto successivo. Si tenga
comunque presente che molti dischi hanno una funzione simile implementata a
livello hardware, questa è realizzata a livello di sistema operativo e va
eventualmente ad aggiungersi alla precedente.

Una seconda opzione importante è \texttt{-d} che consente di attivare o
disattivare l'accesso in DMA al disco, che permette di aumentare notevolmente
le prestazioni; un valore 1 abilita il DMA, ed un valore 0 lo disabilita. In
genere questa funzionalità viene attivata automaticamente dal modulo del
kernel che gestisce il bus ATA, insieme alla modalità di trasferimento dati
controllabile con l'opzione \texttt{-X}. Può capitare comunque che per alcuni
dischi ed alcuni chipset questa funzionalità possa causare problemi o non sia
impostata correttamente al valore migliore, nel qual caso si può disabilitare
l'accesso in DMA con questa opzione, ed impostare esplicitamente una modalità
di trasferimento dati con \texttt{-X}.

\begin{table}[!htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|l|p{10cm}|}
    \hline
    \textbf{Parametro} & \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \textit{look-ahead}  &\texttt{-A}& legge e imposta la modalità di
                          \textit{read-ahead} hardware, normalmente abilitata
                          in modo automatico, (1 abilitata, 0 disabilitata).\\ 
    \textit{readahead}   &\texttt{-a}& legge e imposta il numero di settori in
                          \textit{read-ahead}.\\ 
    \textit{busstate}    &\texttt{-b}& legge e imposta lo stato del bus; il
                          valore 1 indica un bus attivo, 0 un bus disattivo.\\ 
    \textit{APM\_level}  &\texttt{-B}& legge e imposta le modalità di risparmio
                           energetico con un valore da 1 a 255; un valore più
                           basso implica maggiore risparmio energetico, fino a
                           127 il disco può essere anche spento, con 255 si
                           disabilita il risparmio energetico.\\ 
    \textit{IO\_support} &\texttt{-c}& legge e imposta la modalità di I/O a
                           32 bit; il valore 0 la disattiva, il valore 1 la
                           attiva in modalità standard, il valore 3 la attiva
                           con una funzione di sincronizzazione richiesta da
                           alcuni chipset.\\
    \textit{using\_dma}  &\texttt{-d}& legge e imposta l'uso del DMA per le
                           operazioni di I/O su disco; il valore 0 la
                           disattiva, il valore 1 la attiva.\\
    \textit{keepsettings}&\texttt{-k}& legge ed imposta il flag di
                           mantenimento delle impostazioni del disco
                           effettuate con le opzioni \texttt{-d},
                           \texttt{-m}, \texttt{-u}, un valore 0 le scarta in
                           caso di reset o spegnimento, un valore 1 le
                           mantiene.\\
    \textit{multcount}   &\texttt{-m}& legge ed imposta il numero di settori
                           trasferiti nella singola operazione di I/O; il
                           valore 0 disabilita il trasferimento multiplo,
                           prende valori potenze di due fino ad un massimo che
                           dipende dal supporto del disco.\\ 
    \textit{acoustic}    &\texttt{-M}& legge ed imposta il livello di
                           rumorosità, secondo le funzionalità AAM
                           (\textit{Automatic Acoustic Management}) presenti
                           nei dischi recenti, prende un valore intero da 0 a
                           254, con un valore più basso che richiede una
                           minore rumorosità, ottenuta diminuendo la velocità
                           di rotazione dei dischi a scapito delle
                           prestazioni.\footnotemark\\
    \textit{max sectors} &\texttt{-N}& legge ed imposta il numero massimo di
                           settori visibili, una funzionalità, chiamata
                           \textit{Host Protected  Area}, che consente di
                           mascherare una parte del disco al sistema
                           operativo, di solito usata dai costruttori per
                           mantenervi software diagnostico o di ripristino; i
                           cambiamenti, a meno di non anteporre la lettera
                           ``\texttt{p}'' al valore specificato, sono
                           temporanei e vengono persi con un riavvio o un
                           reset del disco.\\ 
%    \textit{nowerr}      &\texttt{-n}& legge ed imposta il flag che indica al
%                           driver del disco di ignorare gli errori di
%                           scrittura.\\
    \textit{readonly}    &\texttt{-r}& legge ed imposta il flag di sola
                           lettura per il disco, il valore 0 disattiva la sola
                           lettura, il valore 1 la attiva.\\ 
    \textit{unmaskirq}   &\texttt{-u}& legge ed imposta il flag di blocco
                           degli interrupt durante le operazioni di I/O; il
                           valore 0 mantiene il blocco, il valore 1 lo
                           disattiva.\\
    \textit{write-caching}&\texttt{-W}& legge ed imposta l'uso della cache di
                           scrittura dei dischi; il valore 0 la disattiva, il
                           valore 1 la attiva.\\
    \hline
  \end{tabular}
  \caption{Principali parametri accessibili con \texttt{hdparm} in lettura e
    scrittura e relative opzioni.}
  \label{tab:hdparm_getset_options}
\end{table}

\footnotetext{la gran parte dei dischi supporta solo un numero di stati
  ridotto, spesso soltanto due \texttt{fast} (massime prestazioni) e
  \texttt{quiet} (bassa rumorosità) oltre eventualmente uno stato di
  spegnimento; per questi sono stati riservati rispettivamente i valori 254,
  128 e 0; ma essendo prevista la possibilità di estensioni l'opzione permette
  l'uso di un valore intero generico.}

Un'altra opzione importante per le prestazioni è \texttt{-m} che imposta il
numero di settori ottenibili in un singolo trasferimento di dati in DMA, una
funzionalità presente in molti dischi moderni, che consente di ottenere una
maggiore velocità di trasferimento dati, con un numero inferiore di interrupt
di I/O. A seconda dei casi si possono ottenere miglioramenti fra il 5 ed il
50\%, anche se con alcuni dischi si sono riscontrati peggioramenti. I valori
che si possono specificare per questa opzione dipendono dal tipo di disco, ed
in genere variano in potenza di 2 da 2 ad un massimo che può essere ottenuto
dalle caratteristiche del disco usando l'opzione \texttt{-i} (viene riportato
nell'output del comando alla voce \textit{MaxMultSect}). In genere valori di
16 o 32, se supportati, sono ottimali.

Un'altra opzione significativa rispetto alle prestazioni è \texttt{-u}, con
cui si può eliminare il mascheramento degli interrupt durante l'I/O su disco;
il default (con il valore 0) prevede infatti il blocco di altri interrupt,
cosa che può causare delle latenze nella risposta del sistema; eliminandolo
(col valore 1) si migliora la reattività del sistema al costo di una minore
velocità di trasferimento. Questa opzione è però potenzialmente pericolosa
dato che alcuni chipset possono non tollerare l'aumento delle latenze nell'I/O
su disco, dando luogo a perdita di dati con conseguente corruzione del
filesystem.

Si tenga presente però che i cambiamenti effettuati con \texttt{hdparm} non
sono permanenti, ed eventuali impostazioni vengono perse oltre che con lo
spegnimento anche in caso di reset del disco; questo come salvaguardia in caso
di impostazioni sbagliate; è possibile però richiedere ai dischi, usando
l'opzione \texttt{-k}, di preservare le impostazioni effettuate con le opzioni
\texttt{-d}, \texttt{-m}, \texttt{-u} così da non doverle rieffettuare;
ovviamente si deve evitare di attivare questa funzionalità fintanto che non si
è certi della validità delle impostazioni correnti. Inoltre è possibile su
alcune distribuzioni utilizzare il file di configurazione
\index{configurazione!\texttt{/etc/hdparm.conf}} \texttt{hdparm.conf} per
mantenere le impostazioni che dovranno essere eseguite al riavvio della
macchina, per il formato si consulti la relativa pagina di manuale.

Un elenco degli altri principali parametri modificabili con specifiche opzioni
di \texttt{hdparm} nelle modalità appena descritte, con una breve spiegazione
del relativo significato è illustrato in tab.~\ref{tab:hdparm_getset_options};
in prima colonna si è riportato il nome utilizzato dal comando nella stampa
dei valori del parametro ed in seconda colonna la opzione corrispondente. 

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-g}& mostra la geometria del disco, se applicato ad una
                 partizione il numero di settori ed il settore di inizio.\\ 
    \texttt{-i}& stampa le informazioni sul dispositivo come viste dal
                 kernel.\\  
    \texttt{-I}& stampa le informazioni sul dispositivo interrogando
                 direttamente lo stesso sul bus.\\ 
    \texttt{-t}& esegue una stima delle prestazioni di lettura del disco.\\ 
    \texttt{-T}& esegue una stima delle prestazioni di trasferimento dati con
                 il bus.\\ 
    \texttt{-X}& imposta la modalità di trasferimento dati per i dischi,
                 utilizzando come argomento uno dei valori ottenuti con  l'uso
                 dell'opzione \texttt{-i}.\footnotemark\\ 
    \texttt{-z}& forza il kernel ad eseguire una rilettura della tabella delle
                 partizioni.\\ 
    \hline
  \end{tabular}
  \caption{Principali opzioni generiche del comando \texttt{hdparm}.}
  \label{tab:hdparm_generic_option}
\end{table}

\footnotetext{in particolare nelle righe \textit{PIO mode}, \textit{DMA mode}
  e \textit{UDMA mode}, si tenga presente comunque che tutti i dischi moderni
  riconoscono ed utilizzano automaticamente la migliore modalità di
  trasferimento disponibile, e che modificare queste impostazioni può essere
  molto pericoloso portare ad una massiccia corruzione dei dati.}

Oltre alle modifiche dei parametri appena illustrate, \texttt{hdparm} supporta
una serie di ulteriori comandi diagnostici e di controllo. In particolare con
l'opzione \texttt{-i} si possono ottenere una serie di informazioni relative
al dispositivo, comprensive di nome del modello, numero di serie, geometria,
modalità del trasferimento dati, ecc. così come viste dal kernel; se invece si
usa l'opzione \texttt{-I} le informazioni vengono richieste direttamente al
dispositivo stesso tramite il bus, e stampate.\footnote{questa opzione, nella
  forma \texttt{-{}-Istdin}, consente di stampare le stesse informazioni
  leggendole dallo \textit{standard input}, nel formato prodotto dal comando
  stesso con l'opzione \texttt{-{}-Istdout}, o da \texttt{sdparm} con
  l'opzione \texttt{-HHH}.}

Altre opzioni interessanti sono \texttt{-t} e \texttt{-T} che permettono di
eseguire delle stime sulle prestazioni dei dischi; si tenga presente che per
una minima attendibilità occorre eseguire più volte questi test su un sistema
inattivo. Con \texttt{-t} si ha una stima della massima velocità di lettura
dal disco, mentre con \texttt{-T} si stima la massima velocità di
trasferimento fra processore, memoria e bus della macchina. 

Si sono riassunte le più comuni fra queste altre opzioni generiche in
tab.~\ref{tab:hdparm_generic_option}, oltre a queste \texttt{hdparm} prevede
molte altre opzioni che consentono di intervenire a basso livello sulle
diverse funzionalità dell'interfaccia IDE/ATA; in quasi tutti i casi però
l'impostazione di valori sbagliati può condurre a conseguenze disastrose con
il rischio di una corruzione massiccia del filesystem ospitato sul disco,
pertanto si lascia la trattazione di tutte le opzioni specialistiche alla
pagina di manuale.

Benché alcune funzionalità siano accessibili anche attraverso \texttt{hdparm},
in maniera abbastanza completa per i dischi SATA, ma molto limitata nel caso
di dischi SCSI o chiavette USB che non supportano le modalità di
compatibilità, il protocollo SCSI prevede dei meccanismi generici per inviare
comandi di controllo ai dispositivi, che questi siano dischi, CD, nastri. Per
questo motivo è disponibile un apposito comando
\index{comando!\texttt{sdparm}} \texttt{sdparm} che, se usato con i dischi,
consente l'accesso ai parametri e l'invio di comandi di basso livello in
maniera analoga ad \texttt{hdparm}, usando direttamente il protocollo SCSI.

La comprensione del funzionamento di \texttt{sdparm} richiede però un minimo
di conoscenza dei meccanismi previsti dal protocollo SCSI per mantenere le
informazioni e modificarle, il che rende l'uso del comando piuttosto
complesso.  Le informazioni relative ad un dispositivo sono infatti
disponibili in due modalità diverse; il primo è quello delle cosiddette pagine
VPD (\textit{Vital Product Data}), che contengono soltanto informazioni
descrittive non modificabili. Il secondo meccanismo è quello delle cosiddette
\textit{mode pages} che contengono informazioni e parametri che si possono
modificare per effettuare le impostazioni volute.

In entrambi i casi la quantità di informazione è estremamente ampia e non è
possibile documentare in questa sede i dettagli disponibili per l'infinita
serie di parametri accessibili al comando (che sono oltre 500, distribuiti fra
le pagine VPD e \textit{mode pages}). Per questo motivo lo stesso
\texttt{sdparm} supporta una opzione generica \texttt{-e} (o
\texttt{-{}-enumerate}) che consente di elencare tutte le pagine presenti
nelle sue tabelle interne, associandole a degli opportuni identificativi
alfanumerici, che poi potranno essere usati per farvi riferimento; in questo
caso il comando ignora un eventuale file di dispositivo passato come
argomento.

Se invocato solo con \texttt{-e} il comando stampa soltanto la lista delle
cosiddette \textit{mode pages} ``\textsl{generiche}'', cioè quelle attinenti
funzionalità generali indipendenti dal tipo di hardware utilizzato. Oltre a
queste infatti esistono sia delle \textit{mode pages} specifiche attinenti il
singolo dispositivo SCSI, create dal produttore, che delle \textit{mode pages}
associate alle varie tecnologie di interconnessione dei dispositivi, come lo
SCSI classico, il \textit{Fiber Channel}, il \textit{Serial Attached SCSI}, il
\textit{Serial ATA}. Un esempio del risultato di questo comando è il seguente:
\begin{Console}
anarres:~# \textbf{sdparm --enumerate}
Mode pages:
  bc   0x1c,0x01  Background control (SBC)
  ca   0x08       Caching (SBC)
  cms  0x2a       CD/DVD (MM) capabilities and mechanical status (MMC)
  co   0x0a       Control
  coe  0x0a,0x01  Control extension
  ...
\end{Console}
in cui, sotto una riga di intestazione che descrive a quale gruppo di pagine
si fa riferimento, viene stampato l'elenco delle pagine presenti su tre
colonne che riportano rispettivamente un identificativo alfanumerico (in
genere l'acronimo del nome esteso), il codice numerico ed un nome esteso della
pagina, usualmente quello con cui questa viene descritta nei standard di
riferimento.

Per ottenere invece la lista delle pagine VPD occorre aggiungere a \texttt{-e}
l'opzione \texttt{-i} (o \texttt{-{}-inquiry}). Se invece a \texttt{-e} si
aggiunge l'opzione \texttt{-l} (o \texttt{-{}-long}) si otterrà la lista
completa di tutte le \textit{mode pages} presenti, ed anche la lista dei
produttori e dei meccanismi di trasporto riconosciuti dal comando a loro volta
associati a degli identificativi alfanumerici.  Si possono poi usare in
combinazione con \texttt{-e} le opzioni \texttt{-M} (o \texttt{-{}-vendor}) e
\texttt{-t} (o \texttt{-{}-transport}) per restringere la selezione
rispettivamente alle \textit{mode pages} relative ad un produttore o a una
tecnologia di trasporto, indicati con i relativi identificativi alfanumerici
(quelli che si ottengono con \texttt{sdparm -e -l}).  Infine l'uso
dell'opzione \texttt{-a} (o \texttt{-{}-all}) fa stampare invece degli
identificativi delle pagine quelli associati ai singoli parametri in essa
contenuti.

Una volta che si siano identificate le pagine che interessano, si potranno
ottenere le informazioni ed i valori dei parametri in esse contenuti
utilizzando l'opzione \texttt{-p} (o \texttt{-{}-page}); questa prende come
argomento o l'identificativo alfanumerico o il codice numerico ottenuti con
\texttt{-e} e stampa tutti i parametri ed i relativi valori presenti nella
pagina stessa. Si è riportato in tab.~\ref{tab:sdparm_pages_names} un elenco
delle pagine più rilevanti; si tenga presente infine che quando si richiedono
i dati di una pagina è necessario passare al comando il dispositivo di cui si
vogliono ottenere i parametri come argomento.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Pagina} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{di}& \textit{Device identification}, la pagina VPD che contiene le
                 informazioni con i dati identificativi del dispositivo,
                 stampata di default con l'opzione \texttt{-i}.\\ 
    \texttt{sv}& \textit{Supported VPD pages}, la pagina che contiene la lista
                 delle pagine VPD supportate.\\
    \texttt{rw}& \textit{Read write error recovery}, la \textit{mode page}
                 che contiene i parametri relativi alla gestione degli errori
                 di accesso.\\ 
    \texttt{ca}& \textit{Caching}, la \textit{mode page} che contiene i
                 parametri relativi alla gestione della cache dei dati.\\ 
    \texttt{co}& \textit{Control}, la \textit{mode page} che contiene i
                 parametri di controllo del dispositivo.\\ 
    \texttt{po}& \textit{Power condition}, la \textit{mode page} che contiene i
                 parametri di controllo del risparmio energetico.\\ 
    \hline
  \end{tabular}
  \caption{Le \textit{mode pages} e le pagine VPD più rilevanti.}
  \label{tab:sdparm_pages_names}
\end{table}

Data la complessità con cui le informazioni sono distribuite nelle varie
pagine \texttt{sdparm}, se usato senza nessuna opzione e passando soltanto
l'argomento del file di dispositivo, stampa una selezione dei parametri più
significativi relativi alle \textit{mode pages} più rilevanti; ad esempio per
un disco \textit{Serial ATA} si otterrà qualcosa del tipo:
\begin{Console}
anarres:~# \textbf{sdparm /dev/sda}
    /dev/sda: ATA       ST3250310AS       3.AA
Read write error recovery mode page:
  AWRE        1
  ARRE        0
  PER         0
Caching (SBC) mode page:
  WCE         1
  RCD         0
Control mode page:
  SWP         0
\end{Console}
in cui nella prima riga vengono riportati i dati di base del dispositivo, ed a
seguire i nomi estesi delle \textit{mode pages} ed al di sotto su due colonne
gli identificativi alfanumerici ed i valori dei parametri.

In genere nella lettura si fa uso anche dell'opzione \texttt{-l} che consente
di ottenere una terza colonna con i nomi estesi dei parametri (di cui
generalmente gli identificativi costituiscono un acronimo), se poi si vogliono
ottenere tutte le \textit{mode pages} e tutti i parametri disponibili per il
dispositivo, si può usare l'opzione \texttt{-a} (o \texttt{-{}-all}). Per
accedere alle informazioni mantenute nelle pagine VPD si deve invece usare
l'opzione \texttt{-i} che da sola stampa dati di identificazione del
dispositivo (cioè il contenuto della pagina \texttt{di}). Se la si usa unita a
\texttt{-a} stampa invece l'elenco delle pagine VPD disponibili, vale a dire
il contenuto della pagina \texttt{sv}.

In genere si usano le informazioni delle pagine VPD per ottenere i dati
relativi ai vari dispositivi: in sostanza l'opzione \texttt{-i} di
\texttt{sdparm} è l'equivalente delle opzioni \texttt{-i} e \texttt{-I} di
\texttt{hdparm}. Non esistono invece delle opzioni specifiche relative alle
impostazioni dei dispositivi in quanto, come accennato, queste vengono
effettuate modificando gli opportuni parametri nelle \textit{mode pages}. A
questi, oltre ad un valore corrente, è associato un flag che indica la
possibilità o meno di modificarlo,\footnote{alcuni parametri sono determinati
  dallo stato del dispositivo e non sono modificabili dall'utente.} un valore
di default stabilito dal produttore ed un valore \textsl{salvato}, che è
quello che verrà usato al successivo reset del dispositivo stesso. Le
operazioni di impostazione avvengono indicando a \texttt{sdparm} quale
parametro modificare usando il relativo identificativo alfanumerico (quello
che si può ottenere con le opzioni viste finora).

Le opzioni che consentono di operare sul singolo parametro sono tre: con
\texttt{-g} (o \texttt{-{}-get}), seguita dall'identificativo del parametro,
se ne ottiene il valore, con \texttt{-s} (o \texttt{-{}-set}) se ne imposta il
valore, da specificare in forma di assegnazione all'identificativo del
parametro: i valori sono sempre numerici, ed espressi in forma decimale, a
meno di non apporvi il prefisso \texttt{0x} per usare la notazione
esadecimale. Infine se a questa si abbina \texttt{-S} (o \texttt{-{}-save}) il
valore specificato verrà impostato oltre che come valore corrente anche come
valore salvato. Si possono poi ripristinare tutti i parametri di una
\textit{mode page} (da indicare con \texttt{-p}) ai rispettivi valori di
default usando l'opzione \texttt{-D} (o \texttt{-{}-defaults}).

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Parametro} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{AWRE}& \textit{Automatic Write Reallocation Enabled} controlla la
                   riallocazione automatica dei settori danneggiati in caso di
                   errori di scrittura (1 abilita, 0 disabilita, con default
                   1).\\ 
    \texttt{ARRE}& \textit{Automatic Read Reallocation Enabled} controlla la
                   riallocazione automatica dei settori danneggiati in caso di
                   errori di lettura (1 abilita, 0 disabilita, con default
                   1).\\ 
%    \texttt{PER} & \textit{Post Error}.\\ 
    \texttt{WCE} & \textit{Write Cache Enable} controlla la cache di
                   scrittura, (1 abilita, 0 disabilita, con default 1), è
                   equivalente all'opzione \texttt{-W} di \texttt{hdparm}.\\
%    \texttt{RCD} & \textit{Read Cache Disable}.\\
%    \texttt{SWP} & \textit{Software Write Protect}.\\
    \texttt{DRA} & \textit{Disable Read Ahead}, controlla il
                   \textit{read-ahead} del disco, (1 disabilita, 0 abilita,
                   con default 0), è equivalente all'opzione \texttt{-A} di
                   \texttt{hdparm}.\\
    \hline
  \end{tabular}
  \caption{I parametri più rilevanti per le impostazioni con \texttt{sdparm}.}
  \label{tab:sdparm_parameters_names}
\end{table}

Così se si vuole impostare il \textit{write caching} del disco (equivalente
dell'opzione \texttt{-W} di \texttt{hdparm}) si potrà usare il comando
\begin{Example}
sdparm --set WCE=1 /dev/sda
\end{Example}
e per effettuare un test delle impostazioni (in cui si esegue un controllo
della validità dei valori richiesti) senza eseguirle effettivamente si può
aggiungere l'opzione \texttt{-d} (o \texttt{-{}-dummy}).  Come per le
\textit{mode pages} e le pagine VPD anche solo fare elenco di tutti i
possibili parametri di configurazione e del loro significato va al di là delle
possibilità di questo testo; si sono riportati in
tab.~\ref{tab:sdparm_parameters_names} alcuni fra i più rilevanti.

Infine \texttt{sdparm} permette di inviare ai dispositivi, attraverso il
protocollo SCSI, una serie di comandi specifici usando l'opzione \texttt{-C}
(o \texttt{-{}-command}); a questa deve seguire come parametro il nome del
comando. I comandi definiti, che non è detto siano applicabili a qualunque
dispositivo (alcuni infatti sono specifici dei masterizzatori) sono riportati
in tab.~\ref{tab:sdparm_command_names} insieme alla spiegazione del relativo
significato.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Comando} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{capacity}& richiede la capacità del supporto, riportando
                       il numero di blocchi, la loro dimensione e la
                       dimensione totale in Mb.\\ 
    \texttt{eject}   & ferma il supporto (se in rotazione) e lo espelle.\\  
    \texttt{load}    & carica il supporto e lo mette in rotazione.\\
%    \texttt{profile} & elenca la lista dei profili disponibili supportati da
%                       un CD/DVD (ad esempio DVD+R e DVD-RAM).\\
    \texttt{ready}   & esegue una interrogazione per verificare se il
                       dispositivo è pronto ad una risposta (cosa che non
                       avviene se ad esempio si è fermato un disco).\\
    \texttt{sense}   & richiede alcune informazioni relative al
                       dispositivo,\footnotemark come le informazioni
                       sull'alimentazione o lo stato di progresso di un
                       comando lento (come una formattazione).\\
%    \texttt{speed}   & .\\
    \texttt{start}   & avvia il supporto, mettendolo in rotazione.\\
    \texttt{stop}    & ferma il supporto, bloccandone la rotazione, è 
                       equivalente a \texttt{hdparm -y}.\\
    \texttt{sync}    & scarica i buffer interni del dispositivo
                       con l'immediata scrittura dei dati sul supporto, è
                       equivalente a \texttt{hdparm -f}.\\
    \texttt{unlock}  & indica al dispositivo di consentire la rimozione del
                       supporto (da usare come ultima risorsa su un
                       dispositivo bloccato), equivalente a 
                       \texttt{hdparm -L0}.\\
    \hline
  \end{tabular}
  \caption{I nomi dei comandi per l'opzione \texttt{-C} di \texttt{sdparm}.}
  \label{tab:sdparm_command_names}
\end{table}

\footnotetext{si tratta in questo caso di uno specifico comando del
  protocollo, denominato \textit{REQUEST SENSE SCSI}, che richiede alcuni dati
  relativi al dispositivo detti appunto \textit{sense data}.}



\subsection{Il ridimensionamento di filesystem e partizioni}
\label{sec:filesystem_resize}

Abbiamo già incontrato in sez.~\ref{sec:RAID_mdadm}, con l'accrescimento di un
RAID software, ed in sez.~\ref{sec:adv_LVM_logical_volume}, con la possibilità
di modificare le dimensioni di un volume logico di LVM, due casi in cui un
dispositivo contenente un filesystem può cambiare dimensioni. In entrambi i
casi si è sottolineato come questo cambiamento non comporti anche
l'adattamento del filesystem alle nuove dimensioni; questo infatti quando
viene creato organizza le sue strutture interne assumendo che il dispositivo
su cui si trova abbia una certa dimensione, che è quella rilevata a quel
momento.

Per questo motivo le operazioni di modifica delle dimensioni di un
dispositivo, che sia questo un RAID software, un volume logico di LVM, o
semplicemente una partizione di cui si sia spostata la fine con i comandi di
sez.~\ref{sec:partitioning}, devono essere sempre accompagnate dalle
conseguenti operazioni di modifica del filesystem sottostante. Ed in
particolare si deve tener conto che se aumentare le dimensioni di un
dispositivo non ha nessun effetto sul filesystem in esso contenuto, il ridurle
senza prima aver ridotto anche quelle del filesystem comporta che questo non
sia più in grado di accedere a parte delle sue strutture (quelle poste nella
parte tolta) con conseguente immediata corruzione dello stesso e probabile
perdita di dati. 

Pertanto quando si vanno ad effettuare operazioni di ridimensionamento è
assolutamente necessario ricordarsi che la corretta sequenza di operazioni non
è la stessa se si compie un allargamento o una riduzione. Nel primo caso
infatti occorre prima allargare il dispositivo e poi il filesystem, mentre nel
secondo occorre prima ridurre il filesystem e poi il dispositivo.

La possibilità di ridimensionare un filesystem dipende dalla presenza di un
opportuno programma, specifico per ciascun tipo di filesystem, in grado di
svolgere questo compito. Correntemente la gran parte dei filesystem presenti
su Linux (ext2/ext3/ext4, reiserfs, XFS, JFS) è dotata di questa
funzionalità. In generale questa operazione può essere eseguita solo a
filesystem inattivo, cioè senza che questo sia montato, il che comporta degli
ovvi problemi se si vuole ridimensionare quello contenente la directory
radice. Alcuni filesystem però supportano anche il ridimensionamento \textsl{a
  caldo} (cioè senza smontare il filesystem) se questo avviene in
accrescimento.

Come accennato ogni filesystem ha normalmente un suo programma per il
ridimensionamento, fa eccezione JFS, che utilizza una specifica opzione di
montaggio; per ridimensionare un filesystem JFS infatti basterà rimontarlo con
un comando del tipo:
\begin{Example}
mount -t jfs -o remount,resize=10G /dev/vg/home /home
\end{Example}
dove se non si specifica nessun parametro per l'opzione \texttt{resize} il
ridimensionamento viene fatto alla dimensione totale del dispositivo
sottostante. Il ridimensionamento può essere eseguito a caldo come
nell'esempio, ma si tenga presente che JFS, come XFS, non supporta il
restringimento del filesystem, le dimensioni possono soltanto essere
aumentate.

Nel caso di XFS il comando che consente il ridimensionamento del filesystem è
\index{comando!\texttt{xfs\_growfs}} \texttt{xfs\_growfs}, il comando richiede
che si passi come argomento il \textit{mount-point} del filesystem, e funziona
soltanto a caldo, vale a dire richiede che il filesystem sia montato. Come per
JFS non è possibile restringere un filesystem XFS. Se non si specifica nulla
il ridimensionamento avviene al totale della nuova dimensione del dispositivo,
per le opzioni si consulti al solito la pagina di manuale.

Per ridimensionare un filesystem \textit{reiserfs} si deve invece usare il
comando \index{comando!\texttt{resize\_reiserfs}} \texttt{resize\_reiserfs},
passando come argomento il dispositivo contenente il filesystem da
ridimensionare. La nuova dimensione si specifica con l'opzione \texttt{-s}
seguita dal valore, con la solita convenzione dell'iniziale per le unità di
misura per indicare kilobyte, megabyte e gigabyte.  L'opzione supporta anche
l'uso dei segni ``\texttt{+}'' e ``\texttt{-}'' per indicare dei
ridimensionamenti relativi (accrescimenti o riduzioni); se non si specifica
nulla il comando userà la dimensione del dispositivo sottostante.

Il comando permette anche di specificare un dispositivo alternativo su cui
mantenere il giornale con l'opzione \texttt{-j}, e di forzare le operazioni
senza eseguire controlli con \texttt{-f}; per avere più informazioni nel corso
delle operazioni si deve invece usare \texttt{-v}. In caso di accrescimento il
il comando può essere usato a caldo, mentre in caso di riduzione è necessario
smontare il filesystem. 

Infine il comando che permette di ridimensionare un filesystem \textit{ext2},
\textit{ext3} o \textit{ext4}, è \index{comando!\texttt{resize2fs}}
\texttt{resize2fs}. A seconda delle versioni del filesystem il programma può
richiedere che il filesystem sia smontato anche in caso di accrescimento, per
poter fare l'accrescimento a caldo infatti il filesystem deve essere montato
almeno come \textit{ext3} e deve essere stato creato con la presenza della
estensione \texttt{resize\_inode}, vedi tab.~\ref{tab:ext2_options}.

Il comando prende come primo argomento il dispositivo su cui si trova il
filesystem da ridimensionare. Se non viene specificato un secondo argomento
indicante la dimensione da usare il ridimensionamento avviene alla dimensione
corrente del dispositivo, cosa che significa che l'argomento non è necessario
in caso di espansione e lo è in caso di riduzione. La dimensione può essere
indicata con la convenzione sulle unità di misura già illustrata in precedenza
che prevede che queste siano specificate posponendo al numero la relativa
iniziale.

Il comando prevede l'opzione \texttt{-d} per abilitare il debug, che prende
come parametro una bitmask indicante quali informazioni stampare, con
l'opzione \texttt{-p} stampa una percentuale di completamento durante le
operazioni, mentre \texttt{-f} forza le operazioni escludendo alcuni controlli
di sicurezza e \texttt{-F} scarica i dati presenti in cache prima di
iniziare. 

Si tenga presente che anche se i comandi citati sono in genere in grado di
determinare da soli la dimensione di un dispositivo, qualora se ne specifichi
manualmente una eccessiva, si andrà incontro a problemi. Inoltre una volta che
si sia ridotto un filesystem e si proceda al restringimento del dispositivo
sottostante, occorre stare molto attenti a non farlo al di sotto delle
dimensioni date al filesystem.

Infine quando si ridimensiona una partizione per poi ridimensionare il
filesystem occorre anche avere cura che essa continui ad avere lo stesso punto
di inizio, altrimenti i comandi non potranno più trovare i dati del
filesystem. Se questo avviene automaticamente per il RAID e LVM, non
altrettanto accade quando si usa \texttt{fdisk} come abbiamo visto in
sez.~\ref{sec:partitioning} per la manipolazione del contenuto della tabella
delle partizioni. 

Quando su un disco sono già presenti dei dati questo in genere significa che
al più si potranno cancellare alcune delle partizioni per poi riutilizzare lo
spazio ottenuto o al più allargare o stringere una partizione esistente, posto
che nel primo caso si sia opportunamente ristretto il filesystem in esso
contenuto, e che nel secondo sia disponibile dello spazio libero in coda alla
partizione e si allarghi poi il filesystem. 

Per questo motivo quando si opera direttamente sulle partizioni è più
opportuno usare un comando come \index{comando!\texttt{parted}}
\texttt{parted} che unisce le funzionalità dei comandi per il partizionamento
e di quelli per il ridimensionamento dei file (ed anche di quelli di controllo
e riparazione) e consente non solo la creazione e la cancellazione delle
partizioni, ma anche il loro ridimensionamento e spostamento senza perderne il
contenuto. Una caratteristica interessante del programma è che ne è
disponibile una versione su disco di avvio che consente di ripartizionare un
sistema prima di avviarlo, cosa che permette di operare anche sulla partizione
che contiene il filesystem della radice.

Il programma opera normalmente in modalità interattiva, e lo si può lanciare
direttamente ottenendo un prompt da cui invocare i comandi interni; se non si
specifica nessun argomento esso andrà ad operare sul primo disco, altrimenti
il primo argomento deve essere il file di dispositivo su cui si vuole operare,
a questo può seguire, per una invocazione non interattiva, la riga di comando
che si darebbe dal prompt, ma in questo caso il file di dispositivo deve
essere sempre indicato.

La gran parte dei comandi interni richiedono il passaggio di opportuni
argomenti, il più comune è il numero della partizione su cui operare, che è
quello che abbiamo illustrato in sez.~\ref{sec:partitioning}. Quando è
richiesta l'indicazione di un disco questa deve essere effettuata specificando
il relativo file di dispositivo, mentre l'indicazione di un tipo di filesystem
utilizza gli stessi valori usati per l'opzione \texttt{-t} di \texttt{mount},
ma si tenga presente che le operazioni sui filesystem sono supportate solo per
alcuni di essi.

Infine qualora sia richiesta la specificazione di una dimensione, che questa
sia un punto di inizio, di fine o l'estensione di una partizione, il default
del programma prevede che un valore numerico sia interpretato come numero di
megabyte. Si possono però usare anche altre unità di misura apponendo al
numero i relativi suffissi (ad esempio \texttt{kB} per kilobyte e \texttt{GB}
per gigabyte), si possono inoltre specificare le dimensioni in percentuale con
il suffisso \texttt{\%} ed usare numeri negativi per indicare una dimensione a
partire dal fondo del disco. Tutte le indicazioni relative alle dimensioni
vengono considerate come approssimate, e vengono automaticamente aggiustate in
un intervallo di 500Mb per rispettare la geometria del disco, a meno di non
specificare un valore esatto in numero di settori, usando il suffisso
\texttt{s}.

Il comando principale di \texttt{parted} è \texttt{resize}, che consente di
ridimensionare e spostare una partizione; il comando prevede che si specifichi
la partizione su cui operare seguita dal punto di inizio e da quello di
fine. Il comando non modifica mai il numero della partizione, ma posto che ci
sia lo spazio disponibile sposta i dati e ridimensiona il filesystem per far
si che la partizione indicata inizi e termini nei punti specificati. Si tenga
presente che la combinazione di uno spostamento ed di un ridimensionamento non
è supportata per tutti i filesystem, nel qual caso sarà necessario, prima
eseguire il ridimensionamento senza cambiare il punto di inizio e poi eseguire
lo spostamento della partizione con \texttt{move}. 

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Comando}&\textbf{Significato} \\
    \hline
    \hline
    \texttt{rm}    & cancella una partizione, se si cancella una partizione
                     logica tutte quelle di numero superiore verranno
                     rinominate per coprire il ``\textsl{buco}''.\\   
    \texttt{print}&  stampa la tabella delle partizioni ed alcuni dati
                     riassuntivi sul disco.\\  
    \texttt{cp}    & copia una partizione, prende come primo argomento
                     opzionale il dispositivo sorgente (da specificare con il
                     rispettivo file di dispositivo), i due argomenti
                     successivi indicano la partizione sorgente e quella di
                     destinazione (che fa sempre riferimento al disco
                     corrente).\\
    \texttt{rescue}& recupera una partizione cancellata accidentalmente,
                     richiede che si specifichi approssimativamente il
                     punto di inizio e di fine della stessa, e se identificata
                     chiederà il numero da assegnargli.\\  
    \texttt{resize}& ridimensiona una partizione, richiede il numero della
                     partizione, il punto di inizio e di fine; in caso di
                     estensione lo spazio ulteriore deve essere libero.\\  
    \texttt{select}& consente di selezionare un altro disco; usato in
                     modalità interattiva.\\  
    \texttt{move}  & sposta una partizione, richiede il numero della stessa
                     seguito dal nuovo punto di inizio e di fine; lo spazio
                     dove la partizione viene spostata deve essere libero.\\  
    \texttt{unit}  & cambia l'unità di misura delle dimensioni, usata in
                     modalità interattiva.\\
    \hline
  \end{tabular}
  \caption{I principali comandi di \texttt{parted}.}
  \label{tab:parted_commands}
\end{table}

Un altro comando interessante di \texttt{parted} è \texttt{rescue} che
consente di recuperare una partizione cancellata per errore, il comando
richiede una indicazione approssimata dei punti di inizio e fine della stessa,
ed esegue una ricerca. Una volta identificati i limiti esatti chiede il numero
da assegnare alla partizione recuperata. 

Si sono riportati in tab.~\ref{tab:parted_commands} i comandi di
\texttt{parted} più significativi, insieme ad una breve descrizione del
significato e degli argomenti necessari; si tenga presente che quando un
comando è invocato in modalità interattiva eventuali argomenti mancanti
verranno chiesti sul terminale. Oltre a quelli citati \texttt{parted} supporta
anche altri comandi per eseguire il partizionamento o la creazione dei
filesystem che duplicano le funzionalità dei comandi standard già visti in
sez.~\ref{sec:disk_filesystem_admin} e che perciò non tratteremo. L'elenco può
comunque essere ottenuto dalla pagina di manuale, anche se la documentazione
completa del comando è fornita soltanto nelle pagine \textit{info} (vedi
sez.~\ref{sec:documentazione}), accessibile con \texttt{info parted}.

% TODO trattare i programmi di monitoraggio dello stato dei dischi, smartd&C

\subsection{Dischi e filesystem cifrati}
\label{sec:encrypted_disks}

Una delle problematiche ricorrenti relative alla sicurezza dei dati è la
possibilità di avere una protezione degli stessi anche in caso di smarrimento
o furto della macchina o dei supporti su cui sono memorizzati. L'accesso
fisico ad un disco infatti consente a chiunque di leggerne il contenuto, per
cui non si può assumere che questo accesso sia effettuato sempre sotto il
controllo del proprio sistema operativo.

In questo caso l'unica misura di protezione efficace è la cifratura dei dati,
in modo che essi possano essere riletti soltanto dopo aver effettuato una
opportuna procedura di decifrazione, ovviamente subordinata ad una
identificazione (come l'immissione di una password di sblocco) del
richiedente, in assenza della quale anche il possesso fisico del supporto
rende impossibile l'accesso ai dati stessi. Ovviamente questo non garantisce
nulla fintanto che questi saranno accessibili (ad esempio in caso di
compromissione della macchina su cui si trovano) ma soltanto dalla
impossibilità di poterli riutilizzare una volta che questi saranno stati resi
indisponibili (spegnendo la macchina o disabilitando la decifrazione).

\itindbeg{device~mapper} 

Le modalità in cui si può realizzare tutto ciò sono varie, fra queste spicca
una delle applicazioni più interessanti dell'infrastruttura del \textit{device
  mapper} del kernel, che abbiamo già incontrato a proposito di LVM, che
consente di cifrare interamente il contenuto di un disco o di una
partizione. In questo caso, invece di rimappare lo spazio disponibile sui
dischi fisici in volumi logici, un dispositivo fisico viene rimappato su un
volume cifrato. Questo significa che quanto verrà scritto in chiaro sul volume
cifrato, verrà cifrato e salvato sul disco fisico, e viceversa si potranno
rileggere i dati cifrati dal disco fisico ottenendoli in chiaro sul volume
cifrato.

In questo caso la cifratura dei dati viene effettuata direttamente dal kernel
ed avviene a livello di dispositivo. Questo consente il massimo delle
prestazioni, ed alcune distribuzioni, come Debian e RedHat, offrono questa
possibilità anche in fase di installazione. In tal caso tutte le impostazioni
vengono fatte dal programma di installazione, e le password per abilitare
l'accesso ai dischi cifrati verranno chieste automaticamente all'avvio del
sistema operativo.

\itindend{device~mapper}

Dato che la creazione di un volume cifrato comporta solo la predisposizione
della rimappatura dello stesso su uno specifico dispositivo fisico, si deve
avere ben presente che i precedenti contenuti di quest'ultimo non vengono
modificati dall'operazione. Per questo è necessario eseguire preventivamente
una sovrascrittura completa dei dati del dispositivo fisico con valori
casuali, con comandi come \texttt{shred}, \texttt{dd} o
\texttt{badblocks},\footnote{ad esempio, rifacendosi al dispositivo fisico
  \texttt{/dev/sdd1} si possono usare i comandi \texttt{badblocks -c 10240 -s
    -w -t random -v /dev/sdd1}, \texttt{dd if=/dev/urandom of=/dev/sdd1} o
  \texttt{shred /dev/sdd1} in ordine crescente di paranoia (e di tempo
  impiegato per eseguire l'operazione).} per evitare che si possano
distinguere chiaramente dal contenuto precedente quali sono le nuove parti
cifrate, che verranno sovrascritte solo coi successivi accessi tramite il
nuovo volume cifrato.

Le tecnologie disponibili per la creazione di volumi cifrati con il
\textit{device mapper} sono sostanzialmente due, la cifratura immediata usando
\textit{dm-crypt} e l'uso di LUKS (\textit{Linux Unified Key Setup}), ma
entrambe vengono gestite attraverso lo stesso programma,
\index{comando!\texttt{cryptsetup}} \texttt{cryptsetup}. Esiste in realtà la
possibilità di gestire con \texttt{cryptsetup} anche altre tecnologie di
cifratura non connesse con il \textit{device mapper}, come \textit{loop-AES} e
\textit{TrueCrypt}, che non tratteremo.  La sintassi generale del programma
prevede che esso sia specificato nella forma:
\begin{Example}
cryptsetup comando [opzioni] [argomenti]
\end{Example}
in cui ``\texttt{comando}'' specifica l'azione che dovrà essere eseguita da
\texttt{cryptsetup}, un elenco dei principali comandi disponibili è stato
riportato in tab.~\ref{tab:cryptsetup_actions}.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Comando}&\textbf{Significato} \\
    \hline
    \hline
    \texttt{open}      & crea un volume cifrato del tipo indicato dall'opzione
                         \texttt{-{}-type}, richiede come primo argomento il
                         file di dispositivo sottostante e come secondo
                         argomento il nome del volume cifrato (che comparirà
                         sotto \texttt{/dev/mapper}), richiede che si fornisca
                         la chiave di accesso.\\   
    \texttt{create}    & attiva un volume cifrato con \textit{dm-crypt},
                         equivalente di \texttt{open} con 
                         \texttt{-{}-type plain}. \\
    \texttt{close}     & rimuove un volume cifrato, eliminando la relativa
                         mappatura, richiede come argomento il nome dello
                         stesso, come compare sotto \texttt{/dev/mapper}.\\   
    \texttt{luksFormat}& crea l'intestazione di LUKS sul dispositivo passato
                         come primo argomento, un secondo argomento opzionale
                         indica il file da cui leggere la passphrase di
                         accesso (un ``\texttt{-}'' implica la lettura dallo
                         \textit{standard input}), se non indicato la
                         passphrase viene richiesta due volte sul terminale.\\
    \texttt{luksOpen}  & attiva un volume cifrato con LUKS, equivalente di
                         \texttt{open} con \texttt{-{}-type luks}. \\
    \texttt{luksAddKey}& aggiunge una nuova chiave di accesso (una passphrase)
                         nel primo slot disponibile, richiede come argomento
                         il dispositivo su cui operare, e chiede la passphrase
                         sul terminale.\\
    \texttt{luksClose} & sinonimo di \texttt{close}.\\   
    \texttt{luksDump}  & stampa una lista del contenuto degli slot,
                         consentendo di individuare quelli utilizzati.\\
    \texttt{luksKillSlot}& cancella completamente il contenuto di uno slot
                         eliminandone la chiave contenuta, richiede sempre,
                         per evitare di restare senza accesso, di fornire una
                         delle chiavi restanti.\\    
    \texttt{luksHeaderBackup}& salva una copia binaria della intestazione di
                         LUKS del dispositivo indicato come argomento.\\
    \texttt{luksHeaderRestore}& ripristina la copia binaria (ottenuta da un
                         precedente \texttt{luksHeaderBackup}) sul dispositivo
                         indicato.\\   
    \hline
  \end{tabular}
  \caption{I principali comandi di \texttt{cryptsetup}.}
  \label{tab:cryptsetup_actions}
\end{table}

La scelta del tipo di cifratura deve essere specificata con l'opzione
\texttt{-{}-type} (che prende i valori riportati in
tab.~\ref{tab:cryptsetup_type}) quando si crea il dispositivo cifrato, cosa
che viene fatta con il comando \texttt{open}, che richiede come argomenti
successivi il file di dispositivo del disco sottostante ed il nome da
assegnare al volume cifrato. Esistono tradizionalmente delle ``abbreviazioni''
(utilizzate per compatibilità con le vecchie versioni del comando) come
\texttt{create} che sottintende l'uso di \textit{dm-crypt} e \texttt{luksOpen}
che sottintende l'uso di LUKS.
 
\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|l|}
    \hline
    \textbf{Valore}&\textbf{Tipo} \\
    \hline
    \hline
    \texttt{plain}   & cifratura semplice con \textit{dm-crypt}.\\   
    \texttt{luks}    & cifratura con LUKS.\\   
    \texttt{loopaes} & cifratura con \textit{loop-AES}.\\   
    \texttt{tcrypt}  & cifratura con \textit{TrueCrypt}.\\   
    \hline
  \end{tabular}
  \caption{Tipi di cifratura supportati da \texttt{cryptsetup} (argomenti per
    l'opzione \texttt{-{}-type}).} 
  \label{tab:cryptsetup_type}
\end{table}


Allora se ad esempio si vuole creare un dispositivo cifrato con
\textit{dm-crypt} utilizzando come supporto la partizione \texttt{/dev/sdd1}
(si può usare anche un intero disco, un volume logico ed in generale un
qualunque dispositivo a blocchi) si dovrà usare un comando del tipo:
\begin{Console}
root@monk:~# \textbf{cryptsetup create -y /dev/sdd1 nome}
Enter passphrase: 
Verify passphrase: 
\end{Console}
ed inserita la passphrase si potrà accedere al volume cifrato che verrà reso
disponibile attraverso il dispositivo \texttt{/dev/mapper/nome}. Si tenga
presente che la passphrase non viene mai mostrata sul terminale, per cui, per
evitare il rischio di errori di battitura, la prima volta che si crea un
volume cifrato prima di salvarci sopra dei dati, è opportuno utilizzare
l'opzione \texttt{-y} che richiede una seconda immissione per verifica.

A questo punto si potrà accedere a \texttt{/dev/mapper/nome} come ad un disco
qualunque, e ad esempio crearvi un filesystem, montarlo e salvarvi sopra i
propri dati. Una volta che non ne sia più necessario l'utilizzo si potrà
disattivare la mappatura del volume cifrato attraverso l'uso del comando
\texttt{close} (ovviamente se montato dovrà prima essere smontato) che prende
come unico argomento il nome dello stesso. Per riaccedervi successivamente
basterà ripetere l'operazione di creazione del volume cifrato con il comando
\texttt{open}, anche usando un nome diverso e senza la necessità di usare
l'opzione \texttt{-y}.

Si tenga presente che \textit{dm-crypt} esegue sempre una cifratura immediata
settore per settore utilizzando la passphrase fornita in fase di
creazione/attivazione del dispositivo cifrato, che viene usata direttamente
come chiave dal sottostante algoritmo di cifratura.\footnote{detto algoritmo
  si può specificare usando l'opzione \texttt{-{}-cipher}, ma non vi è alcun
  motivo per cambiare il default che è \texttt{aes-cbc-essiv:sha256}, qualora
  lo si faccia si abbia però cura di annotarselo, perché anch'esso non viene
  memorizzato ed usarne uno diverso comporta l'impossibilità di decifrare il
  contenuto.}  Detta passphrase non viene mai salvata, non vengono fatti
controlli di consistenza e non esistono metadati. Se si immette una passphrase
sbagliata essa verrà comunque accettata ed utilizzata, ottenendo un volume
cifrato che contiene dei dati inintelligibili.

Questo significa anche che non esiste modo di cambiare la passphrase di
cifratura che non sia quello di ricifrare da capo tutto il dispositivo, usando
un \texttt{dd} per leggere dal volume originario, cifrato con la passphrase di
partenza, e scrivere su quello nuovo, cifrato con la nuova passphrase. Tutto
ciò richiede o la presenza di un dispositivo fisico di appoggio di dimensioni
equivalenti per fare l'operazione in due passi, oppure, se si fa l'operazione
utilizzando lo stesso dispositivo (cosa possibile dato che \texttt{dd} legge e
scrive un blocco alla volta per cui prima decifra e poi sovrascrive con la
nuova cifratura) che si accetti il rischio, se il comando viene interrotto per
un qualsiasi motivo, di trovarsi il disco cifrato un po' con la nuova e un po'
con la vecchia passphrase, con una perdita di dati praticamente scontata.

L'uso di LUKS fornisce invece un minimo di infrastruttura in più, in tal caso
infatti la passphrase richiesta in fase di creazione del volume cifrato
(chiamata \textsl{chiave} nella terminologia di LUKS) serve a cifrare la
chiave effettivamente usata dall'algoritmo crittografico, che viene generata
in maniera totalmente casuale e non è nota all'utente. LUKS salva questa
informazione in una intestazione posta all'inizio del dispositivo, che può
contenere fino ad otto di queste ``\textsl{chiavi}'', si potrà pertanto, anche
se la chiave crittografica effettivamente usata è sempre la stessa, utilizzare
fino ad otto passphrase per sbloccarla ed utilizzare il volume cifrato.

Questa differenza rende immediatamente LUKS più sicuro: con \textit{dm-crypt}
la necessità di usare direttamente come chiave crittografica la passphrase,
che è anche quella che occorre memorizzare, rende infatti impossibile o molto
difficile usare un valore completamente casuale. Con LUKS la passphrase serve
solo a decifrare la chiave effettiva, che è completamente casuale e quindi è
praticamente impossibile indovinarla. Inoltre LUKS, avendo la possibilità di
utilizzare più ``\textsl{chiavi}'', consente anche di far usare credenziali
diverse a persone diverse, e cambiarle senza dover ricifrare il dispositivo
sottostante.

A differenza di quanto visto per \textit{dm-crypt} qualora si voglia usare
LUKS occorre prima preparare adeguatamente il dispositivo.  Questo si fa
usando il comando \texttt{luksFormat}, che crea l'intestazione con i dati
necessari ed imposta la prima passphrase di accesso; un possibile esempio è il
comando seguente:
\begin{Console}
root@monk:~# \textbf{cryptsetup luksFormat -y /dev/sdd1}
WARNING!
========
This will overwrite data on /dev/sdd1 irrevocably.

Are you sure? (Type uppercase yes): \textbf{YES}
Enter passphrase: 
Verify passphrase: 
\end{Console}
che crea sul disco sottostante (nel caso \texttt{/dev/sdd1}) l'infrastruttura
necessaria al successivo uso dello stesso come volume cifrato con LUKS.

Alternativamente all'immissione sul terminale, \texttt{luksFormat} e tutti gli
altri comandi che richiedono l'uso di una passphrase possono utilizzare
l'opzione \texttt{-{}-key-file} per effettuare la lettura della stessa dal
file indicato come parametro. Questo permette ad esempio di non bloccare
l'avvio se si deve montare il volume cifrato e nessuno può inserire la
passphrase sul terminale, ma ovviamente chiunque otterrà l'accesso al file
sarà in grado di utilizzare il disco cifrato. Si può utilizzare questo
meccanismo per mettere la chiave su un dispositivo rimovibile rendendo
inaccessibile il volume cifrato in assenza della stesso, o per rendere
inaccessibili a terzi dischi contenenti backup riposti in collocazioni remote.

Una volta creata l'infrastruttura iniziale si potrà aggiungere una nuova
passphrase con il comando \texttt{luksAddKey}, che andrà ad inserire la stessa
nel primo slot libero disponibile (fino ad un massimo di otto) a meno di non
usare l'opzione \texttt{-{}-key-slot} per indicarne esplicitamente uno. Il
comando richiede come argomento il dispositivo fisico e l'immissione di una
passphrase valida sul terminale, chiedendo poi la nuova passphrase da
aggiungere; un esempio è il seguente:
\begin{Console}
root@monk:~# \textbf{cryptsetup luksAddKey /dev/sdd1}
Enter any existing passphrase: 
Enter new passphrase for key slot: 
Verify passphrase: 
\end{Console}
ed anche in questo caso si potrà fornire la passphrase di accesso su un file
con l'opzione \texttt{-{}-key-file} mentre se si vuole fornire la nuova
passphrase su un file questo andrà passato come secondo argomento. 

Una delle caratteristiche di sicurezza più interessanti fornite da LUKS, che
lo rende ancor più resistente ai tentativi di forzatura della passphrase, è
l'uso di un algoritmo crittografico (denominato PBKDF2) che prevede che si
possa richiedere un tempo minimo comunque necessario a decifrare la
chiave. Questo rallenta enormemente la ripetizione dei tentativi di accesso,
rendendo sostanzialmente inutilizzabili i programmi di forzatura delle
password senza avere un impatto significativo nell'uso da parte di una
persona. Questa durata si può impostare in fase di creazione di una passphrase
(quindi con \texttt{luksFormat} o \texttt{luksAddKey}) con l'opzione
\texttt{-i} seguita dal numero di millisecondi; il valore di default è di un
secondo, ma lo si può aumentare a piacere.

Per rimuovere una passphrase occorre invece il comando \texttt{luksKillSlot},
che oltre al dispositivo fisico su cui operare richiede come secondo argomento
il numero di slot da cancellare. Di nuovo verrà richiesta una passphrase di
accesso (o si può usare un file con l'opzione \texttt{-{}-key-file}), ma il
comando non consente di cancellare lo slot su cui questa è
memorizzata. L'elenco degli slot occupati può essere ottenuto usando il
comando \texttt{luksDump} che stampa le informazioni dell'intestazione di
LUKS, con un risultato del tipo:
\begin{Console}
root@monk:~# \textbf{cryptsetup luksDump /dev/sdd1}
LUKS header information for /dev/sdd1
...
Key Slot 0: ENABLED
	Iterations:         	161615
	Salt:               	91 19 9a dd eb 7f 1e 28 e8 e0 c7 1d 36 3a fa b2 
	                      	fe 40 b1 26 77 d9 87 f8 36 5b db 71 a8 41 a3 fc 
	Key material offset:	8
	AF stripes:            	4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED
\end{Console}

Una volta creata l'intestazione di LUKS si potrà ``aprire'' il volume cifrato
con il comando \texttt{luksOpen}, che è l'analogo del precedente
\texttt{create}, in tal caso verrà chiesta una passphrase di accesso, fornita
la quale si otterrà il volume cifrato. Proseguendo il precedente esempio si
potrà usare il comando:
\begin{Console}
root@monk:~# \textbf{cryptsetup luksOpen /dev/sdd1 nome}
Enter passphrase for /dev/sdd1: 
\end{Console}
che una volta fornita una delle passphrase disponibili renderà disponibile il
volume cifrato come \texttt{/dev/mapper/nome},\footnote{a differenza di
  \textit{dm-crypt}, che usa sempre la passphrase fornita, il comando fallisce
  se non si specifica una passphrase corretta.} e si potrà operare su questo
come su un qualunque dispositivo a blocchi (quindi vi si potrà creare un
filesystem, montarlo, smontarlo ecc.).

Qualora si voglia disabilitare l'accesso ad un volume cifrato si potrà
rimuoverlo con il comando \texttt{close} (o anche \texttt{luksClose}, che è un
sinonimo). Ovviamente perché il comando abbia successo occorre che il volume
non sia utilizzato (ad esempio se contiene un filesystem questo non dovrà
essere montato). 

% da finire 


\section{Le quote disco}
\label{sec:disk_quota}

Una delle caratteristiche avanzate della gestione dei dischi presenti fin dal
kernel 2.0 è quella delle quote disco, un meccanismo che consente di limitare
la quantità delle risorse su disco che i singoli utenti (o gruppi) possono
usare.  Tratteremo in questa sezione il loro utilizzo e le relative modalità
di gestione.


\subsection{Visione generale}
\label{sec:adv_quota_intro}

Una delle risorse principali che gli amministratori di sistema devono gestire
è quella dello spazio disco; uno dei problemi più comuni è infatti quello del
riempimento del disco, e questo avviene sovente perché alcuni utenti non si
curano di controllare le risorse che usano, e finiscono per riempire tutto lo
spazio disponibile, a scapito pure degli altri utenti.

Per questo motivo una delle caratteristiche presenti da sempre in sistemi
multiutente è quella di poter imporre delle restrizioni allo spazio disco
utilizzato dai singoli utenti. Nel caso specifico di un sistema unix-like
questo è sempre stato realizzato attraverso le cosiddette \textsl{quote
  disco}, un meccanismo, realizzato nel kernel, che pone delle restrizioni alle
risorse che un singolo utente può utilizzare.

L'idea è che in questo modo esiste un limite di occupazione delle risorse
oltre il quale ogni utente non può andare. La struttura del meccanismo di
controllo opera sia sulla quantità di spazio disco (cioè sul numero di
\textsl{blocchi}) che sul numero di file (cioè sul numero di \textit{inode})
da mettere a disposizione; le due risorse sono completamente indipendenti per
cui è possibile superare il limite sul numero di file occupati pur avendo
ancora spazio disco disponibile.

Le quote sono sempre calcolate per ogni singolo filesystem (che deve
supportare il meccanismo) pertanto è usuale attivarle sul filesystem su cui si
sono piazzate le home degli utenti. Con gli ultimi kernel il supporto è
presente per tutti i filesystem principali. Si tenga presente comunque che se
gli utenti possono scrivere su più filesystem le quote opereranno in maniera
indipendente su ciascuno di essi, e dovranno perciò essere impostate
separatamente.

Un'ultima caratteristica generale delle quote disco è che il controllo sulla
occupazione delle risorse può avvenire sia a livello di un singolo utente
(cioè in base all'\textit{user ID}), che di un gruppo (cioè in base al
\textit{group ID}), che di entrambi.  In pratica, si avrà la possibilità di
utilizzare il disco per aggiungere un certo file se questo è consentito dalla
quota dell'utente cui apparterrà il file in questione o se è consentito dalla
quota di gruppo (sempre per il gruppo di appartenenza del file).


\subsection{Configurazione del sistema delle quote}
\label{sec:adv_quota_conf}

Per poter utilizzare le quote disco occorre anzitutto abilitare il relativo
supporto nel kernel nella sezione \texttt{File systems} della configurazione.
Del sistema esistono due versioni, entrambe supportate per compatibilità,
anche se da anni è in uso soltanto la più recente. Si tenga presente che se si
vogliono usare le quote con NFS occorre che sia stato opportunamente avviato
il relativo demone per la gestione (vedi sez.~\ref{sec:net_NFS_server}).

Il secondo passo per utilizzare il controllo delle quote è segnalarne la
presenza in fase di montaggio del filesystem, perché il kernel sia
successivamente in grado di mantenere i dati relativi all'uso del disco ed
applicare le restrizioni. Questo viene fatto utilizzando due opzioni
specifiche per \texttt{/etc/fstab}: per le quote degli utenti si usa
\texttt{usrquota} mentre per quelle dei gruppi \texttt{grpquota}, un esempio
di utilizzo di queste opzioni è il seguente:
\begin{FileExample}[label=/etc/fstab]
/dev/vg/home    /home    ext3  defaults,usrquota,grpquota       0       1
\end{FileExample}

Una volta abilitato il supporto nel kernel e montato opportunamente il
filesystem il passo successivo è quello di avere presenti nella radice del
relativo filesystem (la directory corrispondente al \textit{mount point}) i
file \texttt{quota.user} e \texttt{quota.group} se si usa la versione 1 del
supporto o i file \texttt{aquota.user} e \texttt{aquota.group} se si usa la
versione 2. È in questa coppia di file che sono mantenuti i dati relativi
all'uso del disco da parte di utenti e gruppi usati dal sistema delle
quote. Questo non è vero per le quote su XFS, in detto filesystem infatti le
quote sono mantenute nei meta-dati interni e non su file visibili.


In generale non è necessario creare questi file a mano anche se alcuni HOWTO
indicano di crearli vuoti con il comando \texttt{touch} se non sono presenti.
Se assente infatti la prima volta che si usa il comando
\index{comando!\texttt{quotacheck}} \texttt{quotacheck} per controllare una
quota il corrispondente file viene creato automaticamente. Il comando deve
essere eseguito su un filesystem montato con le opzioni per le quote prima
della loro abilitazione con \texttt{quotaon}, in modo da ricostruire lo stato
dell'occupazione delle risorse sul disco. Se infatti le informazioni di
\texttt{aquota.user} e \texttt{aquota.group} non sono aggiornate il meccanismo
delle quote non funziona in maniera corretta.

Il comando prende come argomento il file di dispositivo su cui è posto il
filesystem da controllare o il rispettivo \textit{mount point} presente in
\texttt{/etc/fstab}, ma questo argomento può essere tralasciato con l'uso
dell'opzione \texttt{-a} che controlla tutti i filesystem montati, tranne
quelli montati via NFS.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-a} & controlla tutti i filesystem montati.\\
    \texttt{-R} & se specificata con \texttt{-a} non controlla la radice.\\
    \texttt{-F} & controlla le quote nel formato specificato, prende i
                  valori: \texttt{vfsold} (per la versione 1), \texttt{vfsv0}
                  (per la versione 2),  \texttt{rpc} (per le quote su NFS) e
                  \texttt{xfs} (per le quote su XFS).\\
    \texttt{-u} & richiede l'esecuzione del controllo per le sole quote 
                  degli utenti (il default).\\
    \texttt{-g} & richiede l'esecuzione del controllo per le sole quote 
                  dei gruppi.\\
    \texttt{-c} & non legge i file con i dati delle quote esistenti.\\
    \texttt{-v} & riporta lo stato di avanzamento delle operazioni.\\
    \texttt{-m} & forza il controllo delle quote senza rimontare il
                  filesystem in sola lettura.\\
    \texttt{-M} & esegue il controllo anche con il filesystem montato in
                  scrittura se il tentativo di rimontarlo in sola lettura
                  fallisce.\\
    \hline
  \end{tabular}
  \caption{Principali opzioni del comando \texttt{quotacheck}.}
  \label{tab:adv_quotacheck}
\end{table}

Il comando costruisce una tabella con l'uso corrente del disco e la confronta
con i dati memorizzati su \texttt{aquota.user} e \texttt{aquota.group}, a meno
di non usare l'opzione \texttt{-c}, nel qual caso detti file non vengono
letti. Se trova delle incoerenze aggiorna le informazioni. In genere il
comando necessita di montare il filesystem in sola lettura, onde evitare delle
variazioni dello spazio occupato durante il calcolo; si può forzare
l'esecuzione se il filesystem non è montabile in sola lettura usando l'opzione
\texttt{-m}, nel qual caso il calcolo non sarà totalmente attendibile.

Di default il comando opera solo per le quote utente, se si vogliono
controllare solo le quote gruppo occorre specificarlo esplicitamente usando
l'opzione \texttt{-g}, se le si vogliono controllare entrambe va specificata
esplicitamente anche l'opzione \texttt{-u}. Le altre opzioni principali sono
riportate in tab.~\ref{tab:adv_quotacheck}, per l'elenco completo ed i
dettagli al solito si faccia riferimento alla pagina di manuale.

Una volta che si è montata una partizione con il controllo delle quote perché
questo sia applicato è necessaria una attivazione esplicita con il comando
\index{comando!\texttt{quotaon}} \texttt{quotaon}. Come per
\texttt{quotacheck} il comando richiede come argomento uno (o più) file di
dispositivo su cui è situato il filesystem con le quote o l'opzione
\texttt{-a} per attivarli tutti. Il comando prende le opzioni \texttt{-u} e
\texttt{-g} con lo stesso significato di \texttt{quotacheck} per attivare le
quote su utenti e gruppi ed al solito di default sono attivate soltanto quelle
sugli utenti. L'opzione \texttt{-v} aumenta la prolissità del comando
stampando ogni filesystem per il quale si sono attivate le quote, mentre con
\texttt{-p} si stampa solo lo stato delle stesse invece di attivarle.  Per le
altre opzioni ed i dettagli di funzionamento al solito si può fare riferimento
alla pagina di manuale.

In sostanza per poter utilizzare le quote, una volta modificato
\texttt{/etc/fstab} per indicare i filesystem su cui usarle, si dovrà
provvedere a lanciare negli script di avvio (subito dopo il montaggio dei
filesystem) un opportuno script che invochi prima \texttt{quotacheck} e poi
\texttt{quotaon}. Gran parte delle distribuzioni installano automaticamente
uno script di questo tipo con l'installazione dei programmi di controllo delle
quote.\footnote{nel caso di Debian lo script è \texttt{/etc/init.d/quota} e fa
  parte del pacchetto omonimo.}

Il sistema del controllo delle quote può anche essere disabilitato utilizzando
\index{comando!\texttt{quotaoff}} \texttt{quotaoff}. Il comando (che è
equivalente a chiamare \texttt{quotaon} con l'opzione \texttt{-f}) notifica al
kernel la richiesta di non effettuare più controlli sul superamento delle
quote. Il comando prende gli stessi argomenti di \texttt{quotaon} (in realtà
si tratta dello stesso eseguibile, solo invocato con un nome diverso), e le
due opzioni \texttt{-v} e \texttt{-p} hanno lo stesso effetto descritto in
precedenza.


\subsection{Gestione delle quote di utenti e gruppi}
\label{sec:adv_quota_user}

Una volta configurato il supporto delle quote, e attivato lo stesso con quanto
illustrato nella sezione precedente, il passo successivo è quello di impostare
quali restrizioni (sia in termini di spazio disco che di \textit{inode}
disponibili) si vogliono imporre ai vari utenti (o ai gruppi).

Come accennato in sez.~\ref{sec:adv_quota_intro} le quote si applicano in
maniera indipendente per ciascun filesystem, inoltre se si ricorda quanto
illustrato in sez.~\ref{sec:filesystem_create}, un filesystem unix-like ha due
tipi di risorse, i \textsl{blocchi} e gli \textit{inode}, i primi sono
relativi allo spazio disco utilizzabile, i secondi al numero di file, e su
entrambi possono essere applicate delle restrizioni in maniera indipendente.

La struttura del meccanismo delle quote disco prevede la presenza di due
limiti, uno \textsl{morbido} (detto appunto \textit{soft limit}) che può
essere superato per brevi periodi di tempo, ed uno \textsl{duro} (detto
\textit{hard limit}) che non può mai venir superato. Il breve periodo di tempo
durante il quale è possibile superare il primo limite è detto \textsl{periodo
  di grazia} (\textit{grace period}), durante detto periodo è ancora possibile
creare nuovi file o usare spazio disco superando il limite \textsl{morbido},
ma comunque mai al di là del limite \textsl{duro}.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-f} & limita le impostazioni al filesystem specificato.\\ 
    \texttt{-u} & richiede l'impostazione delle quote per un utente.\\
    \texttt{-g} & richiede l'impostazione delle quote per un gruppo.\\
    \texttt{-t} & imposta il \textit{periodo di grazia}.\\
    \texttt{-p} & specifica un utente di riferimento.\\
    \hline
  \end{tabular}
  \caption{Principali opzioni del comando \texttt{edquota}.}
  \label{tab:adv_edquota}
\end{table}

Il programma che permette di impostare le quote (ovviamente solo
all'amministratore) è \index{comando!\texttt{edquota}} \texttt{edquota}, e
nella sua forma più semplice prende come argomento l'utente di cui si vogliono
modificare le quote, il comando infatti per default agisce sulle quote utente,
se si vuole operare su un gruppo occorre specificare l'opzione \texttt{-g}.
Il comando crea un file di testo temporaneo con la rappresentazione delle
quote correnti per l'utente o il gruppo scelto, e lancia l'editor di default
(in genere \texttt{vi} o quello stabilito dalla variabile di ambiente
\texttt{EDITOR}), all'interno del quale apparirà un contenuto del tipo:
\begin{FileExample}
Quotas for user piccardi: 
/dev/hda3: blocks in use: 2594, limits (soft = 5000, hard = 6500) 
         inodes in use: 356, limits (soft = 1000, hard = 1500)
\end{FileExample}
le informazioni riguardo l'uso corrente sono riportate solo per riferimento, e
una loro modifica verrà ignorata, modificando invece i valori dei limiti fra
parentesi, salvando il file ed uscendo dall'editor questi verranno utilizzati
come nuovi limiti. Un limite può essere annullato usando il valore 0.

In realtà il comando consente di specificare come argomenti più utenti (o
gruppi) ed utilizzare l'opzione \texttt{-p} per specificare un utente (o
gruppo) di riferimento le cui impostazioni dovranno essere utilizzate per
tutti gli altri. In questo modo è possibile effettuare una impostazione
generale per un singolo utente senza doverla poi ripetere a mano per tutti gli
altri.

Se non si specifica nulla il comando imposta le quote per tutti i filesystem
che le supportano; si può delimitare l'azione del programma ad un solo
filesystem specificando quest'ultimo (indicato per file di dispositivo) con
l'opzione \texttt{-f}.

Infine con l'opzione \texttt{-t} si può impostare il valore del cosiddetto
\textsl{periodo di grazia}. Si tenga presente che questa è una proprietà
globale che può essere impostata solo a livello di tutti gli utenti (o tutti i
gruppi) di un singolo filesystem. Usando questa opzione di nuovo sarà aperto
un file temporaneo all'interno dell'editor di default, il cui contenuto sarà
qualcosa del tipo:
\begin{FileExample}
Time units may be: days, hours, minutes, or seconds 
Grace period before enforcing soft limits for users: 
/dev/hda2: block grace period: 0 days, file grace period: 0 days 
\end{FileExample}

Con la prima versione della gestione delle quote specificare un valore nullo
per il \textsl{periodo di grazia} significava utilizzare il valore di default
del periodo, pari ad una settimana. Con le nuove versioni è sempre necessario
impostare esplicitamente un limite.  Un elenco delle principali opzioni del
comando \texttt{edquota} è riportato in tab.~\ref{tab:adv_edquota}, per i
dettagli e l'elenco completo si faccia al solito riferimento alla pagina di
manuale.

Una volta attivate le quote ci sono due comandi che permettono di verificarne
lo stato, il primo è \index{comando!\texttt{quota}} \texttt{quota} che
permette ad un utente di verificare le condizioni delle sue quote disco. Il
comando con l'opzione \texttt{-u} (il default, può essere omessa) stampa un
resoconto delle quote utente, se si vuole controllare le quote di gruppo
occorre usare l'opzione \texttt{-g}.

L'amministratore (e solo lui) può anche richiedere il resoconto delle quote di
un altro utente (o di un gruppo, nel qual caso occorre usare l'opzione
\texttt{-g}) specificando quest'ultimo come argomento del comando.  Le altre
opzioni principali di \texttt{quota} sono riportate in
tab.~\ref{tab:adv_quota}, per i dettagli e l'elenco completo si faccia al
solito riferimento alla pagina di manuale.

\begin{table}[htb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|l|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-f} & limita le impostazioni al filesystem specificato.\\ 
    \texttt{-u} & richiede i dati delle quote utente.\\
    \texttt{-g} & richiede i dati delle quote gruppo.\\
    \texttt{-l} & riporta solo le quote su filesystem locali.\\
    \texttt{-q} & stampa le informazioni in modalità \textsl{succinta}.\\
    \hline
  \end{tabular}
  \caption{Principali opzioni del comando \texttt{quota}.}
  \label{tab:adv_quota}
\end{table}

Un secondo comando per il controllo dello stato delle quote è
\index{comando!\texttt{repquota}} \texttt{repquota} che però è ad uso
esclusivo dell'amministratore, in quanto serve a fornire dei rapporti globali
sullo stato delle quote nel sistema riportando i totali per tutti gli utenti.
Un esempio del suo risultato potrebbe essere il seguente:
\begin{Console}
root@monk# \textbf{repquota -a} 
                                Block limits               File limits 
        User            used    soft    hard  grace    used  soft  hard  grace 
        root      --  175419       0       0          14679     0     0 
        bin       --   18000       0       0            735     0     0 
        uucp      --     729       0       0             23     0     0 
        man       --      57       0       0             10     0     0 
        user1     --   13046   15360   19200            806  1500  2250 
        user2     --    2838    5120    6400            377  1000  1500
\end{Console}


Il comando \texttt{repquota} prevede come argomento il filesystem di cui si
vogliono controllare le quote specificato sia tramite \textit{mount-point} che
per dispositivo; questo può essere omesso se si usa l'opzione \texttt{-a} che
controlla tutti i filesystem per cui sono abilitate le quote. Le altre opzioni
servono per lo più a controllare le informazioni che vengono stampate; in
particolare al solito \texttt{-u} e \texttt{-g} consentono di richiedere il
rapporto rispettivamente per quote utenti e quote gruppo.  Un sommario delle
principali opzioni è riportato in tab.~\ref{tab:adv_repquota}, al solito per
l'elenco completo ed i dettagli di funzionamento del comando si può fare
riferimento alla pagina di manuale.

\begin{table}[!h!tb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-a} & elenca i dati per tutti i filesystem in cui
                  \texttt{/etc/mtab} riporta l'uso di quote.\\ 
    \texttt{-u} & elenca i dati delle quote utente.\\
    \texttt{-g} & elenca i dati delle quote gruppo.\\
    \texttt{-n} & non risolve i nomi di utenti e gruppi.\\
    \texttt{-q} & stampa le informazioni in modalità \textsl{succinta}.\\
    \texttt{-s} & adatta le unità di misura per spazio disco e \textit{inode}.\\ 
    \texttt{-v} & riporta maggiori informazioni e stampa i dati delle 
                  quote anche quando non sono usate.\\
    \hline
  \end{tabular}
  \caption{Principali opzioni del comando \texttt{repquota}.}
  \label{tab:adv_repquota}
\end{table}

La gestione delle quote attraverso \texttt{edquota} risulta però abbastanza
scomoda, dovendo passare attraverso l'uso di un editor e modifiche di file di
testo, il che ad esempio rende sostanzialmente inutilizzabile il comando
all'interno di script. Per questo sono stati creati degli altri programmi che
consentono di eseguire l'impostazione delle quote direttamente sulla riga di
comando.

Il primo di questi è \index{comando!\texttt{setquota}} \texttt{setquota}.
Usato nella sua forma elementare il comando prende come argomenti un nome
utente (ma si può usare un gruppo se si specifica l'opzione \texttt{-g})
seguito dai limiti soft e hard per i blocchi e poi da quelli per gli
\textit{inode}. L'ultimo argomento è il filesystem a cui applicare le quote,
che può essere omesso se si usa l'opzione \texttt{-a}. Con l'opzione
\texttt{-b} i limiti delle quote possono essere forniti sullo \textit{standard input}
invece che sulla riga di comando. Un sommario delle principali opzioni è
riportato in tab.~\ref{tab:adv_setquota}, al solito per l'elenco completo ed i
dettagli di funzionamento del comando si può fare riferimento alla pagina di
manuale.

\begin{table}[!h!tb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-a} & applica il comando a tutti i filesystem in cui
                  \texttt{/etc/mtab} riporta l'uso di quote.\\ 
    \texttt{-u} & richiede l'impostazione delle quote utente (indicato per
                  nome o \textit{user ID}).\\
    \texttt{-g} & richiede l'impostazione delle quote gruppo (indicato per
                  nome o \textit{group ID}).\\
    \texttt{-b} & legge i dati delle quote dallo \textit{standard input} invece che
                  dagli argomenti della riga di comando.\\
    \texttt{-t} & imposta il \textsl{periodo di grazia} (in secondi), richiede
                  che si specifichino come argomenti il tempo in secondi per
                  blocchi e \textit{inode}.\\ 
    \hline
  \end{tabular}
  \caption{Principali opzioni del comando \texttt{setquota}.}
  \label{tab:adv_setquota}
\end{table}

Un secondo comando di gestione delle quote, che oltre alle impostazioni può
anche eseguire la visualizzazione delle stesse, è
\index{comando!\texttt{quotatool}} \texttt{quotatool}. L'unico argomento preso
dal comando è il filesystem su cui si vuole operare, che può essere indicato
sia per dispositivo che per \textit{mount-point}. Occorre inoltre indicare
esplicitamente utente o gruppo su cui si vuole operare con le opzioni
\texttt{-u} o \texttt{-g}, cui deve seguire come parametro il nome utente o il
rispettivo \textit{user ID}, a meno che non si sia usata anche l'opzione
\texttt{-t} per impostare il periodo di grazia a livello globale.

\begin{table}[!h!tb]
  \centering
  \footnotesize
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Opzione} & \textbf{Significato} \\
    \hline
    \hline
    \texttt{-u} & imposta le quote utente.\\
    \texttt{-g} & imposta le quote gruppo.\\
    \texttt{-d} & stampa le quote correnti per l'utente o il gruppo.\\
    \texttt{-t} & imposta il \textsl{periodo di grazia}, può essere usato un
                  valore numerico con i prefissi \texttt{+} e \texttt{-} per
                  aumentarlo o diminuirlo ed un suffisso che specifichi le
                  unità di misura (\texttt{seconds}, \texttt{minutes}, ecc.)\\
    \texttt{-i} & indica di modificare le quote per gli \textit{inode}.\\ 
    \texttt{-b} & indica di modificare le quote per i blocchi.\\
    \texttt{-l} & imposta un \textit{hard-limit}.\\
    \texttt{-q} & imposta un \textit{soft-limit}.\\
    \hline
  \end{tabular}
  \caption{Principali opzioni del comando \texttt{quotatool}.}
  \label{tab:adv_quotatool}
\end{table}

Le opzioni \texttt{-i} e \texttt{-b} servono per indicare se si vogliono
impostare le quote dei blocchi o degli \textit{inode}, mentre i valori delle
stesse devono essere specificati come parametri per le opzioni \texttt{-q}
(per il \textit{soft-limit}) e \texttt{-l} (per l'\textit{hard-limit}).  Le
principali opzioni sono riportate in tab.~\ref{tab:adv_quotatool}, per
l'elenco completo ed i dettagli di funzionamento al solito si può fare
riferimento alla pagina di manuale.

% LocalWords:  array redundant arrays of inexpensive disks SLED large expensive
% LocalWords:  linear kernel stripe sull'array stripes IDE all'array dell'array
% LocalWords:  mean between failure controller seek filesystem l'array l'UUID
% LocalWords:  SCSI block devices dev DAC Mylex rd Compaq ida ATA device APM rm
% LocalWords:  support sez raidtools mdadm raiddev sample configuration created
% LocalWords:  with mdtools level nr disks persistent superblock chunk size xFD
% LocalWords:  parity algorithm left symmetric nell'array l'autorilevamento tab
% LocalWords:  kilobyte striping failed raidtab mkraid raidstart raidstop proc
% LocalWords:  cat personalities read ahead sectors active hdc hda blocks get
% LocalWords:  unused UU recovery speed sec raidhotremove dall'array VG save cp
% LocalWords:  hot pluggable raidhotadd Logical like LVM fig group logical PV
% LocalWords:  physical extent PE mapper snapshot pvcreate dd if bs count UUID
% LocalWords:  universal unique IDentifier MAC address lvm pvscan reading all
% LocalWords:  volumes this may take while vg total pvdisplay name secs NOT sda
% LocalWords:  usable available allocatable yes Cur KByte allocated abort sdb
% LocalWords:  pvmove vgcreate vgname kilo gigabyte Mb kb Gb debug vgextend and
% LocalWords:  vgreduce vgchange vgscan mknodes monk found successfully WARNING
% LocalWords:  program does not VGDA your vgdisplay write resizable Act WCE TB
% LocalWords:  alloc vgmerge vgsplit lvcreate terabyte lvolN lvname rw lvscan
% LocalWords:  lvdisplay lvextend lvreduce lvresize lvremove parted ext XFS run
% LocalWords:  reiserfs JFS mount jfs remount resize home fs patch bitmask info
% LocalWords:  cache reiser fdisk inode systems NFS usrquota point cciss fd add
% LocalWords:  grpquota defaults aquota HOWTO touch quotacheck quotaon vfsold
% LocalWords:  vfsv rpc xfs quotaoff soft limit grace period edquota Quotas for
% LocalWords:  limits inodes units days hours minutes seconds before enforcing
% LocalWords:  users repquota used root bin uucp Identifier Piccardi USB dummy
% LocalWords:  setquota quotatool ramdisk manage fail remove superblocco gethen
% LocalWords:  build assemble grow follow Incr plug autodetect homehost Enabled
% LocalWords:  assembly incremental mirror raidN faulty misc urras detail scan
% LocalWords:  num metadata Lenny partitions superblocks alternatively specify
% LocalWords:  to using wildcards desired permissions owner automatically tag
% LocalWords:  new arrays as belonging the local system HOMEHOST instruct where
% LocalWords:  monitoring daemon send alerts MAILADDR definitions existing uuid
% LocalWords:  filename globbing conf config missing resync daemonise syslog is
% LocalWords:  delay oneshot examine query readonly readwrite hdparm SAT sdparm
% LocalWords:  command translation growfs dell'UUID readahead busstate dma DMA
% LocalWords:  keepsettings reset unmaskirq interrupt caching quiet MaxMultSect
% LocalWords:  automatic acoustic host protected UDMA SATA VPD vital product kB
% LocalWords:  pages fiber channel attached anarres control SBC capabilities
% LocalWords:  mechanical extension inquiry long vendor transport page error
% LocalWords:  identification multcount condition Reallocation Enable Disable
% LocalWords:  capacity eject load ready sense sync unlock request move rescue
% LocalWords:  print select unit l'MTBF setphysicalvolumesize pvs pvresize type
% LocalWords:  format areas sequence access AAM supported power AWRE DRA hain
% LocalWords:  filter RedHat shred badblocks crypt unified setup 
% LocalWords:  cryptsetup TrueCrypt plain close luksFormat passphrase luks
% LocalWords:  luksOpen luksAddKey luksClose luksDump luksKillSlot cipher aes
% LocalWords:  luksHeaderBackup luksHeaderRestore cbc essiv sha will you sure
% LocalWords:  overwrite irrevocably uppercase verify key any PBKDF header
% LocalWords:  information iterations salt material DISABLED

%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "corso"
%%% End: 
