doc:it_IT: align Italian translation

Translation for the following patches:

commit c4f4af4094 ("docs: Add documentation for Symbol Namespaces")
commit 36bc683dde ("kernel-doc: rename the kernel-doc directive 'functions' to 'identifiers'")
commit a035d552a9 ("Makefile: Globally enable fall-through warning")
commit b9918bdcac ("Documentation/process: Add fallthrough pseudo-keyword")
commit 58ad30cf91 ("docs: fix reference to core-api/namespaces.rst")
commit fb0e0ffe7f ("Documentation: bring process docs up to date")
commit 7af51678b6 ("docs: deprecated.rst: Add BUG()-family")
commit 7929b9836e ("docs: Remove :c:func: from process/deprecated.rst")
commit 76136e028d ("docs: deprecated.rst: Clean up fall-through details")
commit d8401f504b ("docs: deprecated.rst: Add %p to the list")
commit b1735296ce ("docs: locking: Drop :c:func: throughout")
commit 6adb775599 ("docs: locking: Add 'need' to hardirq section")

Signed-off-by: Federico Vaga <federico.vaga@vaga.pv.it>
Link: https://lore.kernel.org/r/20200430222037.4480-1-federico.vaga@vaga.pv.it
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
This commit is contained in:
Federico Vaga 2020-05-01 00:20:37 +02:00 committed by Jonathan Corbet
parent 16a398d176
commit b67aa4ef68
6 changed files with 287 additions and 159 deletions

View File

@ -515,6 +515,22 @@ internal: *[source-pattern ...]*
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
:internal: :internal:
identifiers: *[ function/type ...]*
Include la documentazione per ogni *function* e *type* in *source*.
Se non vengono esplicitamente specificate le funzioni da includere, allora
verranno incluse tutte quelle disponibili in *source*.
Esempi::
.. kernel-doc:: lib/bitmap.c
:identifiers: bitmap_parselist bitmap_parselist_user
.. kernel-doc:: lib/idr.c
:identifiers:
functions: *[ function ...]*
Questo è uno pseudonimo, deprecato, per la direttiva 'identifiers'.
doc: *title* doc: *title*
Include la documentazione del paragrafo ``DOC:`` identificato dal titolo Include la documentazione del paragrafo ``DOC:`` identificato dal titolo
(*title*) all'interno del file sorgente (*source*). Gli spazi in *title* sono (*title*) all'interno del file sorgente (*source*). Gli spazi in *title* sono
@ -528,15 +544,6 @@ doc: *title*
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
:doc: High Definition Audio over HDMI and Display Port :doc: High Definition Audio over HDMI and Display Port
functions: *function* *[...]*
Dal file sorgente (*source*) include la documentazione per le funzioni
elencate (*function*).
Esempio::
.. kernel-doc:: lib/bitmap.c
:functions: bitmap_parselist bitmap_parselist_user
Senza alcuna opzione, la direttiva kernel-doc include tutti i commenti di Senza alcuna opzione, la direttiva kernel-doc include tutti i commenti di
documentazione presenti nel file sorgente (*source*). documentazione presenti nel file sorgente (*source*).

View File

@ -627,6 +627,24 @@ Alcuni manutentori e sviluppatori potrebbero comunque richiedere
:c:func:`EXPORT_SYMBOL_GPL()` quando si aggiungono nuove funzionalità o :c:func:`EXPORT_SYMBOL_GPL()` quando si aggiungono nuove funzionalità o
interfacce. interfacce.
:c:func:`EXPORT_SYMBOL_NS()`
----------------------------
Definita in ``include/linux/export.h``
Questa è una variate di `EXPORT_SYMBOL()` che permette di specificare uno
spazio dei nomi. Lo spazio dei nomi è documentato in
:doc:`../core-api/symbol-namespaces`
:c:func:`EXPORT_SYMBOL_NS_GPL()`
--------------------------------
Definita in ``include/linux/export.h``
Questa è una variate di `EXPORT_SYMBOL_GPL()` che permette di specificare uno
spazio dei nomi. Lo spazio dei nomi è documentato in
:doc:`../core-api/symbol-namespaces`
Procedure e convenzioni Procedure e convenzioni
======================= =======================

View File

@ -159,17 +159,17 @@ Sincronizzazione in contesto utente
Se avete una struttura dati che verrà utilizzata solo dal contesto utente, Se avete una struttura dati che verrà utilizzata solo dal contesto utente,
allora, per proteggerla, potete utilizzare un semplice mutex allora, per proteggerla, potete utilizzare un semplice mutex
(``include/linux/mutex.h``). Questo è il caso più semplice: inizializzate il (``include/linux/mutex.h``). Questo è il caso più semplice: inizializzate il
mutex; invocate :c:func:`mutex_lock_interruptible()` per trattenerlo e mutex; invocate mutex_lock_interruptible() per trattenerlo e
:c:func:`mutex_unlock()` per rilasciarlo. C'è anche :c:func:`mutex_lock()` mutex_unlock() per rilasciarlo. C'è anche mutex_lock()
ma questa dovrebbe essere evitata perché non ritorna in caso di segnali. ma questa dovrebbe essere evitata perché non ritorna in caso di segnali.
Per esempio: ``net/netfilter/nf_sockopt.c`` permette la registrazione Per esempio: ``net/netfilter/nf_sockopt.c`` permette la registrazione
di nuove chiamate per :c:func:`setsockopt()` e :c:func:`getsockopt()` di nuove chiamate per setsockopt() e getsockopt()
usando la funzione :c:func:`nf_register_sockopt()`. La registrazione e usando la funzione nf_register_sockopt(). La registrazione e
la rimozione vengono eseguite solamente quando il modulo viene caricato la rimozione vengono eseguite solamente quando il modulo viene caricato
o scaricato (e durante l'avvio del sistema, qui non abbiamo concorrenza), o scaricato (e durante l'avvio del sistema, qui non abbiamo concorrenza),
e la lista delle funzioni registrate viene consultata solamente quando e la lista delle funzioni registrate viene consultata solamente quando
:c:func:`setsockopt()` o :c:func:`getsockopt()` sono sconosciute al sistema. setsockopt() o getsockopt() sono sconosciute al sistema.
In questo caso ``nf_sockopt_mutex`` è perfetto allo scopo, in particolar modo In questo caso ``nf_sockopt_mutex`` è perfetto allo scopo, in particolar modo
visto che setsockopt e getsockopt potrebbero dormire. visto che setsockopt e getsockopt potrebbero dormire.
@ -179,19 +179,19 @@ Sincronizzazione fra il contesto utente e i softirq
Se un softirq condivide dati col contesto utente, avete due problemi. Se un softirq condivide dati col contesto utente, avete due problemi.
Primo, il contesto utente corrente potrebbe essere interroto da un softirq, Primo, il contesto utente corrente potrebbe essere interroto da un softirq,
e secondo, la sezione critica potrebbe essere eseguita da un altro e secondo, la sezione critica potrebbe essere eseguita da un altro
processore. Questo è quando :c:func:`spin_lock_bh()` processore. Questo è quando spin_lock_bh()
(``include/linux/spinlock.h``) viene utilizzato. Questo disabilita i softirq (``include/linux/spinlock.h``) viene utilizzato. Questo disabilita i softirq
sul processore e trattiene il *lock*. Invece, :c:func:`spin_unlock_bh()` fa sul processore e trattiene il *lock*. Invece, spin_unlock_bh() fa
l'opposto. (Il suffisso '_bh' è un residuo storico che fa riferimento al l'opposto. (Il suffisso '_bh' è un residuo storico che fa riferimento al
"Bottom Halves", il vecchio nome delle interruzioni software. In un mondo "Bottom Halves", il vecchio nome delle interruzioni software. In un mondo
perfetto questa funzione si chiamerebbe 'spin_lock_softirq()'). perfetto questa funzione si chiamerebbe 'spin_lock_softirq()').
Da notare che in questo caso potete utilizzare anche :c:func:`spin_lock_irq()` Da notare che in questo caso potete utilizzare anche spin_lock_irq()
o :c:func:`spin_lock_irqsave()`, queste fermano anche le interruzioni hardware: o spin_lock_irqsave(), queste fermano anche le interruzioni hardware:
vedere :ref:`Contesto di interruzione hardware <it_hardirq-context>`. vedere :ref:`Contesto di interruzione hardware <it_hardirq-context>`.
Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock
svaniscono e questa macro diventa semplicemente :c:func:`local_bh_disable()` svaniscono e questa macro diventa semplicemente local_bh_disable()
(``include/linux/interrupt.h``), la quale impedisce ai softirq d'essere (``include/linux/interrupt.h``), la quale impedisce ai softirq d'essere
eseguiti. eseguiti.
@ -224,8 +224,8 @@ Differenti tasklet/timer
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
Se un altro tasklet/timer vuole condividere dati col vostro tasklet o timer, Se un altro tasklet/timer vuole condividere dati col vostro tasklet o timer,
allora avrete bisogno entrambe di :c:func:`spin_lock()` e allora avrete bisogno entrambe di spin_lock() e
:c:func:`spin_unlock()`. Qui :c:func:`spin_lock_bh()` è inutile, siete già spin_unlock(). Qui spin_lock_bh() è inutile, siete già
in un tasklet ed avete la garanzia che nessun altro verrà eseguito sullo in un tasklet ed avete la garanzia che nessun altro verrà eseguito sullo
stesso processore. stesso processore.
@ -243,13 +243,13 @@ processore (vedere :ref:`Dati per processore <it_per-cpu>`). Se siete arrivati
fino a questo punto nell'uso dei softirq, probabilmente tenete alla scalabilità fino a questo punto nell'uso dei softirq, probabilmente tenete alla scalabilità
delle prestazioni abbastanza da giustificarne la complessità aggiuntiva. delle prestazioni abbastanza da giustificarne la complessità aggiuntiva.
Dovete utilizzare :c:func:`spin_lock()` e :c:func:`spin_unlock()` per Dovete utilizzare spin_lock() e spin_unlock() per
proteggere i dati condivisi. proteggere i dati condivisi.
Diversi Softirqs Diversi Softirqs
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
Dovete utilizzare :c:func:`spin_lock()` e :c:func:`spin_unlock()` per Dovete utilizzare spin_lock() e spin_unlock() per
proteggere i dati condivisi, che siano timer, tasklet, diversi softirq o proteggere i dati condivisi, che siano timer, tasklet, diversi softirq o
lo stesso o altri softirq: uno qualsiasi di essi potrebbe essere in esecuzione lo stesso o altri softirq: uno qualsiasi di essi potrebbe essere in esecuzione
su un diverso processore. su un diverso processore.
@ -270,40 +270,40 @@ Se un gestore di interruzioni hardware condivide dati con un softirq, allora
avrete due preoccupazioni. Primo, il softirq può essere interrotto da avrete due preoccupazioni. Primo, il softirq può essere interrotto da
un'interruzione hardware, e secondo, la sezione critica potrebbe essere un'interruzione hardware, e secondo, la sezione critica potrebbe essere
eseguita da un'interruzione hardware su un processore diverso. Questo è il caso eseguita da un'interruzione hardware su un processore diverso. Questo è il caso
dove :c:func:`spin_lock_irq()` viene utilizzato. Disabilita le interruzioni dove spin_lock_irq() viene utilizzato. Disabilita le interruzioni
sul processore che l'esegue, poi trattiene il lock. :c:func:`spin_unlock_irq()` sul processore che l'esegue, poi trattiene il lock. spin_unlock_irq()
fa l'opposto. fa l'opposto.
Il gestore d'interruzione hardware non usa :c:func:`spin_lock_irq()` perché Il gestore d'interruzione hardware non ha bisogno di usare spin_lock_irq()
i softirq non possono essere eseguiti quando il gestore d'interruzione hardware perché i softirq non possono essere eseguiti quando il gestore d'interruzione
è in esecuzione: per questo si può usare :c:func:`spin_lock()`, che è un po' hardware è in esecuzione: per questo si può usare spin_lock(), che è un po'
più veloce. L'unica eccezione è quando un altro gestore d'interruzioni più veloce. L'unica eccezione è quando un altro gestore d'interruzioni
hardware utilizza lo stesso *lock*: :c:func:`spin_lock_irq()` impedirà a questo hardware utilizza lo stesso *lock*: spin_lock_irq() impedirà a questo
secondo gestore di interrompere quello in esecuzione. secondo gestore di interrompere quello in esecuzione.
Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock
svaniscono e questa macro diventa semplicemente :c:func:`local_irq_disable()` svaniscono e questa macro diventa semplicemente local_irq_disable()
(``include/asm/smp.h``), la quale impedisce a softirq/tasklet/BH d'essere (``include/asm/smp.h``), la quale impedisce a softirq/tasklet/BH d'essere
eseguiti. eseguiti.
:c:func:`spin_lock_irqsave()` (``include/linux/spinlock.h``) è una variante che spin_lock_irqsave() (``include/linux/spinlock.h``) è una variante che
salva lo stato delle interruzioni in una variabile, questa verrà poi passata salva lo stato delle interruzioni in una variabile, questa verrà poi passata
a :c:func:`spin_unlock_irqrestore()`. Questo significa che lo stesso codice a spin_unlock_irqrestore(). Questo significa che lo stesso codice
potrà essere utilizzato in un'interruzione hardware (dove le interruzioni sono potrà essere utilizzato in un'interruzione hardware (dove le interruzioni sono
già disabilitate) e in un softirq (dove la disabilitazione delle interruzioni già disabilitate) e in un softirq (dove la disabilitazione delle interruzioni
è richiesta). è richiesta).
Da notare che i softirq (e quindi tasklet e timer) sono eseguiti al ritorno Da notare che i softirq (e quindi tasklet e timer) sono eseguiti al ritorno
da un'interruzione hardware, quindi :c:func:`spin_lock_irq()` interrompe da un'interruzione hardware, quindi spin_lock_irq() interrompe
anche questi. Tenuto conto di questo si può dire che anche questi. Tenuto conto di questo si può dire che
:c:func:`spin_lock_irqsave()` è la funzione di sincronizzazione più generica spin_lock_irqsave() è la funzione di sincronizzazione più generica
e potente. e potente.
Sincronizzazione fra due gestori d'interruzioni hardware Sincronizzazione fra due gestori d'interruzioni hardware
-------------------------------------------------------- --------------------------------------------------------
Condividere dati fra due gestori di interruzione hardware è molto raro, ma se Condividere dati fra due gestori di interruzione hardware è molto raro, ma se
succede, dovreste usare :c:func:`spin_lock_irqsave()`: è una specificità succede, dovreste usare spin_lock_irqsave(): è una specificità
dell'architettura il fatto che tutte le interruzioni vengano interrotte dell'architettura il fatto che tutte le interruzioni vengano interrotte
quando si eseguono di gestori di interruzioni. quando si eseguono di gestori di interruzioni.
@ -317,11 +317,11 @@ Pete Zaitcev ci offre il seguente riassunto:
il mutex e dormire (``copy_from_user*(`` o ``kmalloc(x,GFP_KERNEL)``). il mutex e dormire (``copy_from_user*(`` o ``kmalloc(x,GFP_KERNEL)``).
- Altrimenti (== i dati possono essere manipolati da un'interruzione) usate - Altrimenti (== i dati possono essere manipolati da un'interruzione) usate
:c:func:`spin_lock_irqsave()` e :c:func:`spin_unlock_irqrestore()`. spin_lock_irqsave() e spin_unlock_irqrestore().
- Evitate di trattenere uno spinlock per più di 5 righe di codice incluse - Evitate di trattenere uno spinlock per più di 5 righe di codice incluse
le chiamate a funzione (ad eccezione di quell per l'accesso come le chiamate a funzione (ad eccezione di quell per l'accesso come
:c:func:`readb()`). readb()).
Tabella dei requisiti minimi Tabella dei requisiti minimi
---------------------------- ----------------------------
@ -334,7 +334,7 @@ processore alla volta, ma se deve condividere dati con un altro thread, allora
la sincronizzazione è necessaria). la sincronizzazione è necessaria).
Ricordatevi il suggerimento qui sopra: potete sempre usare Ricordatevi il suggerimento qui sopra: potete sempre usare
:c:func:`spin_lock_irqsave()`, che è un sovrainsieme di tutte le altre funzioni spin_lock_irqsave(), che è un sovrainsieme di tutte le altre funzioni
per spinlock. per spinlock.
============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ============== ============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ==============
@ -378,13 +378,13 @@ protetti dal *lock* quando qualche altro thread lo sta già facendo
trattenendo il *lock*. Potrete acquisire il *lock* più tardi se vi trattenendo il *lock*. Potrete acquisire il *lock* più tardi se vi
serve accedere ai dati protetti da questo *lock*. serve accedere ai dati protetti da questo *lock*.
La funzione :c:func:`spin_trylock()` non ritenta di acquisire il *lock*, La funzione spin_trylock() non ritenta di acquisire il *lock*,
se ci riesce al primo colpo ritorna un valore diverso da zero, altrimenti se ci riesce al primo colpo ritorna un valore diverso da zero, altrimenti
se fallisce ritorna 0. Questa funzione può essere utilizzata in un qualunque se fallisce ritorna 0. Questa funzione può essere utilizzata in un qualunque
contesto, ma come :c:func:`spin_lock()`: dovete disabilitare i contesti che contesto, ma come spin_lock(): dovete disabilitare i contesti che
potrebbero interrompervi e quindi trattenere lo spinlock. potrebbero interrompervi e quindi trattenere lo spinlock.
La funzione :c:func:`mutex_trylock()` invece di sospendere il vostro processo La funzione mutex_trylock() invece di sospendere il vostro processo
ritorna un valore diverso da zero se è possibile trattenere il lock al primo ritorna un valore diverso da zero se è possibile trattenere il lock al primo
colpo, altrimenti se fallisce ritorna 0. Nonostante non dorma, questa funzione colpo, altrimenti se fallisce ritorna 0. Nonostante non dorma, questa funzione
non può essere usata in modo sicuro in contesti di interruzione hardware o non può essere usata in modo sicuro in contesti di interruzione hardware o
@ -506,7 +506,7 @@ della memoria che il suo contenuto sono protetti dal *lock*. Questo
caso è semplice dato che copiamo i dati dall'utente e non permettiamo caso è semplice dato che copiamo i dati dall'utente e non permettiamo
mai loro di accedere direttamente agli oggetti. mai loro di accedere direttamente agli oggetti.
C'è una piccola ottimizzazione qui: nella funzione :c:func:`cache_add()` C'è una piccola ottimizzazione qui: nella funzione cache_add()
impostiamo i campi dell'oggetto prima di acquisire il *lock*. Questo è impostiamo i campi dell'oggetto prima di acquisire il *lock*. Questo è
sicuro perché nessun altro potrà accedervi finché non lo inseriremo sicuro perché nessun altro potrà accedervi finché non lo inseriremo
nella memoria. nella memoria.
@ -514,7 +514,7 @@ nella memoria.
Accesso dal contesto utente Accesso dal contesto utente
--------------------------- ---------------------------
Ora consideriamo il caso in cui :c:func:`cache_find()` può essere invocata Ora consideriamo il caso in cui cache_find() può essere invocata
dal contesto d'interruzione: sia hardware che software. Un esempio potrebbe dal contesto d'interruzione: sia hardware che software. Un esempio potrebbe
essere un timer che elimina oggetti dalla memoria. essere un timer che elimina oggetti dalla memoria.
@ -583,15 +583,15 @@ sono quelle rimosse, mentre quelle ``+`` sono quelle aggiunte.
return ret; return ret;
} }
Da notare che :c:func:`spin_lock_irqsave()` disabiliterà le interruzioni Da notare che spin_lock_irqsave() disabiliterà le interruzioni
se erano attive, altrimenti non farà niente (quando siamo già in un contesto se erano attive, altrimenti non farà niente (quando siamo già in un contesto
d'interruzione); dunque queste funzioni possono essere chiamante in d'interruzione); dunque queste funzioni possono essere chiamante in
sicurezza da qualsiasi contesto. sicurezza da qualsiasi contesto.
Sfortunatamente, :c:func:`cache_add()` invoca :c:func:`kmalloc()` con Sfortunatamente, cache_add() invoca kmalloc() con
l'opzione ``GFP_KERNEL`` che è permessa solo in contesto utente. Ho supposto l'opzione ``GFP_KERNEL`` che è permessa solo in contesto utente. Ho supposto
che :c:func:`cache_add()` venga chiamata dal contesto utente, altrimenti che cache_add() venga chiamata dal contesto utente, altrimenti
questa opzione deve diventare un parametro di :c:func:`cache_add()`. questa opzione deve diventare un parametro di cache_add().
Esporre gli oggetti al di fuori del file Esporre gli oggetti al di fuori del file
---------------------------------------- ----------------------------------------
@ -610,7 +610,7 @@ Il secondo problema è il problema del ciclo di vita: se un'altra struttura
mantiene un puntatore ad un oggetto, presumibilmente si aspetta che questo mantiene un puntatore ad un oggetto, presumibilmente si aspetta che questo
puntatore rimanga valido. Sfortunatamente, questo è garantito solo mentre puntatore rimanga valido. Sfortunatamente, questo è garantito solo mentre
si trattiene il *lock*, altrimenti qualcuno potrebbe chiamare si trattiene il *lock*, altrimenti qualcuno potrebbe chiamare
:c:func:`cache_delete()` o peggio, aggiungere un oggetto che riutilizza lo cache_delete() o peggio, aggiungere un oggetto che riutilizza lo
stesso indirizzo. stesso indirizzo.
Dato che c'è un solo *lock*, non potete trattenerlo a vita: altrimenti Dato che c'è un solo *lock*, non potete trattenerlo a vita: altrimenti
@ -710,9 +710,9 @@ Ecco il codice::
} }
Abbiamo incapsulato il contatore di riferimenti nelle tipiche funzioni Abbiamo incapsulato il contatore di riferimenti nelle tipiche funzioni
di 'get' e 'put'. Ora possiamo ritornare l'oggetto da :c:func:`cache_find()` di 'get' e 'put'. Ora possiamo ritornare l'oggetto da cache_find()
col vantaggio che l'utente può dormire trattenendo l'oggetto (per esempio, col vantaggio che l'utente può dormire trattenendo l'oggetto (per esempio,
:c:func:`copy_to_user()` per copiare il nome verso lo spazio utente). copy_to_user() per copiare il nome verso lo spazio utente).
Un altro punto da notare è che ho detto che il contatore dovrebbe incrementarsi Un altro punto da notare è che ho detto che il contatore dovrebbe incrementarsi
per ogni puntatore ad un oggetto: quindi il contatore di riferimenti è 1 per ogni puntatore ad un oggetto: quindi il contatore di riferimenti è 1
@ -727,8 +727,8 @@ Ci sono un certo numbero di operazioni atomiche definite
in ``include/asm/atomic.h``: queste sono garantite come atomiche su qualsiasi in ``include/asm/atomic.h``: queste sono garantite come atomiche su qualsiasi
processore del sistema, quindi non sono necessari i *lock*. In questo caso è processore del sistema, quindi non sono necessari i *lock*. In questo caso è
più semplice rispetto all'uso degli spinlock, benché l'uso degli spinlock più semplice rispetto all'uso degli spinlock, benché l'uso degli spinlock
sia più elegante per casi non banali. Le funzioni :c:func:`atomic_inc()` e sia più elegante per casi non banali. Le funzioni atomic_inc() e
:c:func:`atomic_dec_and_test()` vengono usate al posto dei tipici operatori di atomic_dec_and_test() vengono usate al posto dei tipici operatori di
incremento e decremento, e i *lock* non sono più necessari per proteggere il incremento e decremento, e i *lock* non sono più necessari per proteggere il
contatore stesso. contatore stesso.
@ -820,7 +820,7 @@ al nome di cambiare abbiamo tre possibilità:
- Si può togliere static da ``cache_lock`` e dire agli utenti che devono - Si può togliere static da ``cache_lock`` e dire agli utenti che devono
trattenere il *lock* prima di modificare il nome di un oggetto. trattenere il *lock* prima di modificare il nome di un oggetto.
- Si può fornire una funzione :c:func:`cache_obj_rename()` che prende il - Si può fornire una funzione cache_obj_rename() che prende il
*lock* e cambia il nome per conto del chiamante; si dirà poi agli utenti *lock* e cambia il nome per conto del chiamante; si dirà poi agli utenti
di usare questa funzione. di usare questa funzione.
@ -878,11 +878,11 @@ Da notare che ho deciso che il contatore di popolarità dovesse essere
protetto da ``cache_lock`` piuttosto che dal *lock* dell'oggetto; questo protetto da ``cache_lock`` piuttosto che dal *lock* dell'oggetto; questo
perché è logicamente parte dell'infrastruttura (come perché è logicamente parte dell'infrastruttura (come
:c:type:`struct list_head <list_head>` nell'oggetto). In questo modo, :c:type:`struct list_head <list_head>` nell'oggetto). In questo modo,
in :c:func:`__cache_add()`, non ho bisogno di trattenere il *lock* di ogni in __cache_add(), non ho bisogno di trattenere il *lock* di ogni
oggetto mentre si cerca il meno popolare. oggetto mentre si cerca il meno popolare.
Ho anche deciso che il campo id è immutabile, quindi non ho bisogno di Ho anche deciso che il campo id è immutabile, quindi non ho bisogno di
trattenere il lock dell'oggetto quando si usa :c:func:`__cache_find()` trattenere il lock dell'oggetto quando si usa __cache_find()
per leggere questo campo; il *lock* dell'oggetto è usato solo dal chiamante per leggere questo campo; il *lock* dell'oggetto è usato solo dal chiamante
che vuole leggere o scrivere il campo name. che vuole leggere o scrivere il campo name.
@ -907,7 +907,7 @@ Questo è facile da diagnosticare: non è uno di quei problemi che ti tengono
sveglio 5 notti a parlare da solo. sveglio 5 notti a parlare da solo.
Un caso un pochino più complesso; immaginate d'avere una spazio condiviso Un caso un pochino più complesso; immaginate d'avere una spazio condiviso
fra un softirq ed il contesto utente. Se usate :c:func:`spin_lock()` per fra un softirq ed il contesto utente. Se usate spin_lock() per
proteggerlo, il contesto utente potrebbe essere interrotto da un softirq proteggerlo, il contesto utente potrebbe essere interrotto da un softirq
mentre trattiene il lock, da qui il softirq rimarrà in attesa attiva provando mentre trattiene il lock, da qui il softirq rimarrà in attesa attiva provando
ad acquisire il *lock* già trattenuto nel contesto utente. ad acquisire il *lock* già trattenuto nel contesto utente.
@ -1006,12 +1006,12 @@ potreste fare come segue::
spin_unlock_bh(&list_lock); spin_unlock_bh(&list_lock);
Primo o poi, questo esploderà su un sistema multiprocessore perché un Primo o poi, questo esploderà su un sistema multiprocessore perché un
temporizzatore potrebbe essere già partiro prima di :c:func:`spin_lock_bh()`, temporizzatore potrebbe essere già partiro prima di spin_lock_bh(),
e prenderà il *lock* solo dopo :c:func:`spin_unlock_bh()`, e cercherà e prenderà il *lock* solo dopo spin_unlock_bh(), e cercherà
di eliminare il suo oggetto (che però è già stato eliminato). di eliminare il suo oggetto (che però è già stato eliminato).
Questo può essere evitato controllando il valore di ritorno di Questo può essere evitato controllando il valore di ritorno di
:c:func:`del_timer()`: se ritorna 1, il temporizzatore è stato già del_timer(): se ritorna 1, il temporizzatore è stato già
rimosso. Se 0, significa (in questo caso) che il temporizzatore è in rimosso. Se 0, significa (in questo caso) che il temporizzatore è in
esecuzione, quindi possiamo fare come segue:: esecuzione, quindi possiamo fare come segue::
@ -1032,9 +1032,9 @@ esecuzione, quindi possiamo fare come segue::
spin_unlock_bh(&list_lock); spin_unlock_bh(&list_lock);
Un altro problema è l'eliminazione dei temporizzatori che si riavviano Un altro problema è l'eliminazione dei temporizzatori che si riavviano
da soli (chiamando :c:func:`add_timer()` alla fine della loro esecuzione). da soli (chiamando add_timer() alla fine della loro esecuzione).
Dato che questo è un problema abbastanza comune con una propensione Dato che questo è un problema abbastanza comune con una propensione
alle corse critiche, dovreste usare :c:func:`del_timer_sync()` alle corse critiche, dovreste usare del_timer_sync()
(``include/linux/timer.h``) per gestire questo caso. Questa ritorna il (``include/linux/timer.h``) per gestire questo caso. Questa ritorna il
numero di volte che il temporizzatore è stato interrotto prima che numero di volte che il temporizzatore è stato interrotto prima che
fosse in grado di fermarlo senza che si riavviasse. fosse in grado di fermarlo senza che si riavviasse.
@ -1116,7 +1116,7 @@ chiamata ``list``::
wmb(); wmb();
list->next = new; list->next = new;
La funzione :c:func:`wmb()` è una barriera di sincronizzazione delle La funzione wmb() è una barriera di sincronizzazione delle
scritture. Questa garantisce che la prima operazione (impostare l'elemento scritture. Questa garantisce che la prima operazione (impostare l'elemento
``next`` del nuovo elemento) venga completata e vista da tutti i processori ``next`` del nuovo elemento) venga completata e vista da tutti i processori
prima che venga eseguita la seconda operazione (che sarebbe quella di mettere prima che venga eseguita la seconda operazione (che sarebbe quella di mettere
@ -1127,7 +1127,7 @@ completamente il nuovo elemento; oppure che lo vedano correttamente e quindi
il puntatore ``next`` deve puntare al resto della lista. il puntatore ``next`` deve puntare al resto della lista.
Fortunatamente, c'è una funzione che fa questa operazione sulle liste Fortunatamente, c'è una funzione che fa questa operazione sulle liste
:c:type:`struct list_head <list_head>`: :c:func:`list_add_rcu()` :c:type:`struct list_head <list_head>`: list_add_rcu()
(``include/linux/list.h``). (``include/linux/list.h``).
Rimuovere un elemento dalla lista è anche più facile: sostituiamo il puntatore Rimuovere un elemento dalla lista è anche più facile: sostituiamo il puntatore
@ -1138,7 +1138,7 @@ l'elemento o lo salteranno.
list->next = old->next; list->next = old->next;
La funzione :c:func:`list_del_rcu()` (``include/linux/list.h``) fa esattamente La funzione list_del_rcu() (``include/linux/list.h``) fa esattamente
questo (la versione normale corrompe il vecchio oggetto, e non vogliamo che questo (la versione normale corrompe il vecchio oggetto, e non vogliamo che
accada). accada).
@ -1146,9 +1146,9 @@ Anche i lettori devono stare attenti: alcuni processori potrebbero leggere
attraverso il puntatore ``next`` il contenuto dell'elemento successivo attraverso il puntatore ``next`` il contenuto dell'elemento successivo
troppo presto, ma non accorgersi che il contenuto caricato è sbagliato quando troppo presto, ma non accorgersi che il contenuto caricato è sbagliato quando
il puntatore ``next`` viene modificato alla loro spalle. Ancora una volta il puntatore ``next`` viene modificato alla loro spalle. Ancora una volta
c'è una funzione che viene in vostro aiuto :c:func:`list_for_each_entry_rcu()` c'è una funzione che viene in vostro aiuto list_for_each_entry_rcu()
(``include/linux/list.h``). Ovviamente, gli scrittori possono usare (``include/linux/list.h``). Ovviamente, gli scrittori possono usare
:c:func:`list_for_each_entry()` dato che non ci possono essere due scrittori list_for_each_entry() dato che non ci possono essere due scrittori
in contemporanea. in contemporanea.
Il nostro ultimo dilemma è il seguente: quando possiamo realmente distruggere Il nostro ultimo dilemma è il seguente: quando possiamo realmente distruggere
@ -1156,15 +1156,15 @@ l'elemento rimosso? Ricordate, un lettore potrebbe aver avuto accesso a questo
elemento proprio ora: se eliminiamo questo elemento ed il puntatore ``next`` elemento proprio ora: se eliminiamo questo elemento ed il puntatore ``next``
cambia, il lettore salterà direttamente nella spazzatura e scoppierà. Dobbiamo cambia, il lettore salterà direttamente nella spazzatura e scoppierà. Dobbiamo
aspettare finché tutti i lettori che stanno attraversando la lista abbiano aspettare finché tutti i lettori che stanno attraversando la lista abbiano
finito. Utilizziamo :c:func:`call_rcu()` per registrare una funzione di finito. Utilizziamo call_rcu() per registrare una funzione di
richiamo che distrugga l'oggetto quando tutti i lettori correnti hanno richiamo che distrugga l'oggetto quando tutti i lettori correnti hanno
terminato. In alternative, potrebbe essere usata la funzione terminato. In alternative, potrebbe essere usata la funzione
:c:func:`synchronize_rcu()` che blocca l'esecuzione finché tutti i lettori synchronize_rcu() che blocca l'esecuzione finché tutti i lettori
non terminano di ispezionare la lista. non terminano di ispezionare la lista.
Ma come fa l'RCU a sapere quando i lettori sono finiti? Il meccanismo è Ma come fa l'RCU a sapere quando i lettori sono finiti? Il meccanismo è
il seguente: innanzi tutto i lettori accedono alla lista solo fra la coppia il seguente: innanzi tutto i lettori accedono alla lista solo fra la coppia
:c:func:`rcu_read_lock()`/:c:func:`rcu_read_unlock()` che disabilita la rcu_read_lock()/rcu_read_unlock() che disabilita la
prelazione così che i lettori non vengano sospesi mentre stanno leggendo prelazione così che i lettori non vengano sospesi mentre stanno leggendo
la lista. la lista.
@ -1253,12 +1253,12 @@ codice RCU è un po' più ottimizzato di così, ma questa è l'idea di fondo.
} }
Da notare che i lettori modificano il campo popularity nella funzione Da notare che i lettori modificano il campo popularity nella funzione
:c:func:`__cache_find()`, e ora non trattiene alcun *lock*. Una soluzione __cache_find(), e ora non trattiene alcun *lock*. Una soluzione
potrebbe essere quella di rendere la variabile ``atomic_t``, ma per l'uso potrebbe essere quella di rendere la variabile ``atomic_t``, ma per l'uso
che ne abbiamo fatto qui, non ci interessano queste corse critiche perché un che ne abbiamo fatto qui, non ci interessano queste corse critiche perché un
risultato approssimativo è comunque accettabile, quindi non l'ho cambiato. risultato approssimativo è comunque accettabile, quindi non l'ho cambiato.
Il risultato è che la funzione :c:func:`cache_find()` non ha bisogno di alcuna Il risultato è che la funzione cache_find() non ha bisogno di alcuna
sincronizzazione con le altre funzioni, quindi è veloce su un sistema sincronizzazione con le altre funzioni, quindi è veloce su un sistema
multi-processore tanto quanto lo sarebbe su un sistema mono-processore. multi-processore tanto quanto lo sarebbe su un sistema mono-processore.
@ -1271,9 +1271,9 @@ riferimenti.
Ora, dato che il '*lock* di lettura' di un RCU non fa altro che disabilitare Ora, dato che il '*lock* di lettura' di un RCU non fa altro che disabilitare
la prelazione, un chiamante che ha sempre la prelazione disabilitata fra le la prelazione, un chiamante che ha sempre la prelazione disabilitata fra le
chiamate :c:func:`cache_find()` e :c:func:`object_put()` non necessita chiamate cache_find() e object_put() non necessita
di incrementare e decrementare il contatore di riferimenti. Potremmo di incrementare e decrementare il contatore di riferimenti. Potremmo
esporre la funzione :c:func:`__cache_find()` dichiarandola non-static, esporre la funzione __cache_find() dichiarandola non-static,
e quel chiamante potrebbe usare direttamente questa funzione. e quel chiamante potrebbe usare direttamente questa funzione.
Il beneficio qui sta nel fatto che il contatore di riferimenti no Il beneficio qui sta nel fatto che il contatore di riferimenti no
@ -1293,10 +1293,10 @@ singolo contatore. Facile e pulito.
Se questo dovesse essere troppo lento (solitamente non lo è, ma se avete Se questo dovesse essere troppo lento (solitamente non lo è, ma se avete
dimostrato che lo è devvero), potreste usare un contatore per ogni processore dimostrato che lo è devvero), potreste usare un contatore per ogni processore
e quindi non sarebbe più necessaria la mutua esclusione. Vedere e quindi non sarebbe più necessaria la mutua esclusione. Vedere
:c:func:`DEFINE_PER_CPU()`, :c:func:`get_cpu_var()` e :c:func:`put_cpu_var()` DEFINE_PER_CPU(), get_cpu_var() e put_cpu_var()
(``include/linux/percpu.h``). (``include/linux/percpu.h``).
Il tipo di dato ``local_t``, la funzione :c:func:`cpu_local_inc()` e tutte Il tipo di dato ``local_t``, la funzione cpu_local_inc() e tutte
le altre funzioni associate, sono di particolare utilità per semplici contatori le altre funzioni associate, sono di particolare utilità per semplici contatori
per-processore; su alcune architetture sono anche più efficienti per-processore; su alcune architetture sono anche più efficienti
(``include/asm/local.h``). (``include/asm/local.h``).
@ -1324,11 +1324,11 @@ da un'interruzione software. Il gestore d'interruzione non utilizza alcun
enable_irq(irq); enable_irq(irq);
spin_unlock(&lock); spin_unlock(&lock);
La funzione :c:func:`disable_irq()` impedisce al gestore d'interruzioni La funzione disable_irq() impedisce al gestore d'interruzioni
d'essere eseguito (e aspetta che finisca nel caso fosse in esecuzione su d'essere eseguito (e aspetta che finisca nel caso fosse in esecuzione su
un altro processore). Lo spinlock, invece, previene accessi simultanei. un altro processore). Lo spinlock, invece, previene accessi simultanei.
Naturalmente, questo è più lento della semplice chiamata Naturalmente, questo è più lento della semplice chiamata
:c:func:`spin_lock_irq()`, quindi ha senso solo se questo genere di accesso spin_lock_irq(), quindi ha senso solo se questo genere di accesso
è estremamente raro. è estremamente raro.
.. _`it_sleeping-things`: .. _`it_sleeping-things`:
@ -1336,7 +1336,7 @@ Naturalmente, questo è più lento della semplice chiamata
Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni? Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni?
========================================================================= =========================================================================
Molte funzioni del kernel dormono (in sostanza, chiamano ``schedule()``) Molte funzioni del kernel dormono (in sostanza, chiamano schedule())
direttamente od indirettamente: non potete chiamarle se trattenere uno direttamente od indirettamente: non potete chiamarle se trattenere uno
spinlock o avete la prelazione disabilitata, mai. Questo significa che spinlock o avete la prelazione disabilitata, mai. Questo significa che
dovete necessariamente essere nel contesto utente: chiamarle da un dovete necessariamente essere nel contesto utente: chiamarle da un
@ -1354,23 +1354,23 @@ dormire.
- Accessi allo spazio utente: - Accessi allo spazio utente:
- :c:func:`copy_from_user()` - copy_from_user()
- :c:func:`copy_to_user()` - copy_to_user()
- :c:func:`get_user()` - get_user()
- :c:func:`put_user()` - put_user()
- :c:func:`kmalloc(GFP_KERNEL) <kmalloc>` - kmalloc(GFP_KERNEL) <kmalloc>`
- :c:func:`mutex_lock_interruptible()` and - mutex_lock_interruptible() and
:c:func:`mutex_lock()` mutex_lock()
C'è anche :c:func:`mutex_trylock()` che però non dorme. C'è anche mutex_trylock() che però non dorme.
Comunque, non deve essere usata in un contesto d'interruzione dato Comunque, non deve essere usata in un contesto d'interruzione dato
che la sua implementazione non è sicura in quel contesto. che la sua implementazione non è sicura in quel contesto.
Anche :c:func:`mutex_unlock()` non dorme mai. Non può comunque essere Anche mutex_unlock() non dorme mai. Non può comunque essere
usata in un contesto d'interruzione perché un mutex deve essere rilasciato usata in un contesto d'interruzione perché un mutex deve essere rilasciato
dallo stesso processo che l'ha acquisito. dallo stesso processo che l'ha acquisito.
@ -1380,11 +1380,11 @@ Alcune funzioni che non dormono
Alcune funzioni possono essere chiamate tranquillamente da qualsiasi Alcune funzioni possono essere chiamate tranquillamente da qualsiasi
contesto, o trattenendo un qualsiasi *lock*. contesto, o trattenendo un qualsiasi *lock*.
- :c:func:`printk()` - printk()
- :c:func:`kfree()` - kfree()
- :c:func:`add_timer()` e :c:func:`del_timer()` - add_timer() e del_timer()
Riferimento per l'API dei Mutex Riferimento per l'API dei Mutex
=============================== ===============================
@ -1444,14 +1444,14 @@ prelazione
bh bh
Bottom Half: per ragioni storiche, le funzioni che contengono '_bh' nel Bottom Half: per ragioni storiche, le funzioni che contengono '_bh' nel
loro nome ora si riferiscono a qualsiasi interruzione software; per esempio, loro nome ora si riferiscono a qualsiasi interruzione software; per esempio,
:c:func:`spin_lock_bh()` blocca qualsiasi interuzione software sul processore spin_lock_bh() blocca qualsiasi interuzione software sul processore
corrente. I *Bottom Halves* sono deprecati, e probabilmente verranno corrente. I *Bottom Halves* sono deprecati, e probabilmente verranno
sostituiti dai tasklet. In un dato momento potrà esserci solo un sostituiti dai tasklet. In un dato momento potrà esserci solo un
*bottom half* in esecuzione. *bottom half* in esecuzione.
contesto d'interruzione contesto d'interruzione
Non è il contesto utente: qui si processano le interruzioni hardware e Non è il contesto utente: qui si processano le interruzioni hardware e
software. La macro :c:func:`in_interrupt()` ritorna vero. software. La macro in_interrupt() ritorna vero.
contesto utente contesto utente
Il kernel che esegue qualcosa per conto di un particolare processo (per Il kernel che esegue qualcosa per conto di un particolare processo (per
@ -1461,12 +1461,12 @@ contesto utente
che hardware. che hardware.
interruzione hardware interruzione hardware
Richiesta di interruzione hardware. :c:func:`in_irq()` ritorna vero in un Richiesta di interruzione hardware. in_irq() ritorna vero in un
gestore d'interruzioni hardware. gestore d'interruzioni hardware.
interruzione software / softirq interruzione software / softirq
Gestore di interruzioni software: :c:func:`in_irq()` ritorna falso; Gestore di interruzioni software: in_irq() ritorna falso;
:c:func:`in_softirq()` ritorna vero. I tasklet e le softirq sono entrambi in_softirq() ritorna vero. I tasklet e le softirq sono entrambi
considerati 'interruzioni software'. considerati 'interruzioni software'.
In soldoni, un softirq è uno delle 32 interruzioni software che possono In soldoni, un softirq è uno delle 32 interruzioni software che possono

View File

@ -23,18 +23,18 @@ ogni due o tre mesi viene effettuata un rilascio importante del kernel.
I rilasci più recenti sono stati: I rilasci più recenti sono stati:
====== ================= ====== =================
4.11 Aprile 30, 2017 5.0 3 marzo, 2019
4.12 Luglio 2, 2017 5.1 5 maggio, 2019
4.13 Settembre 3, 2017 5.2 7 luglio, 2019
4.14 Novembre 12, 2017 5.3 15 settembre, 2019
4.15 Gennaio 28, 2018 5.4 24 novembre, 2019
4.16 Aprile 1, 2018 5.5 6 gennaio, 2020
====== ================= ====== =================
Ciascun rilascio 4.x è un importante rilascio del kernel con nuove Ciascun rilascio 5.x è un importante rilascio del kernel con nuove
funzionalità, modifiche interne dell'API, e molto altro. Un tipico funzionalità, modifiche interne dell'API, e molto altro. Un tipico
rilascio 4.x contiene quasi 13,000 gruppi di modifiche con ulteriori rilascio contiene quasi 13,000 gruppi di modifiche con ulteriori
modifiche a parecchie migliaia di linee di codice. La 4.x. è pertanto la modifiche a parecchie migliaia di linee di codice. La 5.x. è pertanto la
linea di confine nello sviluppo del kernel Linux; il kernel utilizza un sistema linea di confine nello sviluppo del kernel Linux; il kernel utilizza un sistema
di sviluppo continuo che integra costantemente nuove importanti modifiche. di sviluppo continuo che integra costantemente nuove importanti modifiche.
@ -55,8 +55,8 @@ verrà descritto dettagliatamente più avanti).
La finestra di inclusione resta attiva approssimativamente per due settimane. La finestra di inclusione resta attiva approssimativamente per due settimane.
Al termine di questo periodo, Linus Torvald dichiarerà che la finestra è Al termine di questo periodo, Linus Torvald dichiarerà che la finestra è
chiusa e rilascerà il primo degli "rc" del kernel. chiusa e rilascerà il primo degli "rc" del kernel.
Per il kernel che è destinato ad essere 2.6.40, per esempio, il rilascio Per il kernel che è destinato ad essere 5.6, per esempio, il rilascio
che emerge al termine della finestra d'inclusione si chiamerà 2.6.40-rc1. che emerge al termine della finestra d'inclusione si chiamerà 5.6-rc1.
Questo rilascio indica che il momento di aggiungere nuovi componenti è Questo rilascio indica che il momento di aggiungere nuovi componenti è
passato, e che è iniziato il periodo di stabilizzazione del prossimo kernel. passato, e che è iniziato il periodo di stabilizzazione del prossimo kernel.
@ -76,22 +76,23 @@ Mentre le correzioni si aprono la loro strada all'interno del ramo principale,
il ritmo delle modifiche rallenta col tempo. Linus rilascia un nuovo il ritmo delle modifiche rallenta col tempo. Linus rilascia un nuovo
kernel -rc circa una volta alla settimana; e ne usciranno circa 6 o 9 prima kernel -rc circa una volta alla settimana; e ne usciranno circa 6 o 9 prima
che il kernel venga considerato sufficientemente stabile e che il rilascio che il kernel venga considerato sufficientemente stabile e che il rilascio
finale 2.6.x venga fatto. A quel punto tutto il processo ricomincerà. finale venga fatto. A quel punto tutto il processo ricomincerà.
Esempio: ecco com'è andato il ciclo di sviluppo della versione 4.16 Esempio: ecco com'è andato il ciclo di sviluppo della versione 5.4
(tutte le date si collocano nel 2018) (tutte le date si collocano nel 2018)
============== ======================================= ============== =======================================
Gennaio 28 4.15 rilascio stabile 15 settembre 5.3 rilascio stabile
Febbraio 11 4.16-rc1, finestra di inclusione chiusa 30 settembre 5.4-rc1, finestra di inclusione chiusa
Febbraio 18 4.16-rc2 6 ottobre 5.4-rc2
Febbraio 25 4.16-rc3 13 ottobre 5.4-rc3
Marzo 4 4.16-rc4 20 ottobre 5.4-rc4
Marzo 11 4.16-rc5 27 ottobre 5.4-rc5
Marzo 18 4.16-rc6 3 novembre 5.4-rc6
Marzo 25 4.16-rc7 10 novembre 5.4-rc7
Aprile 1 4.17 rilascio stabile 17 novembre 5.4-rc8
24 novembre 5.4 rilascio stabile
============== ======================================= ============== =======================================
In che modo gli sviluppatori decidono quando chiudere il ciclo di sviluppo e In che modo gli sviluppatori decidono quando chiudere il ciclo di sviluppo e
@ -108,43 +109,44 @@ tipo di perfezione difficilmente viene raggiunta; esistono troppe variabili
in un progetto di questa portata. Arriva un punto dove ritardare il rilascio in un progetto di questa portata. Arriva un punto dove ritardare il rilascio
finale peggiora la situazione; la quantità di modifiche in attesa della finale peggiora la situazione; la quantità di modifiche in attesa della
prossima finestra di inclusione crescerà enormemente, creando ancor più prossima finestra di inclusione crescerà enormemente, creando ancor più
regressioni al giro successivo. Quindi molti kernel 4.x escono con una regressioni al giro successivo. Quindi molti kernel 5.x escono con una
manciata di regressioni delle quali, si spera, nessuna è grave. manciata di regressioni delle quali, si spera, nessuna è grave.
Una volta che un rilascio stabile è fatto, il suo costante mantenimento è Una volta che un rilascio stabile è fatto, il suo costante mantenimento è
affidato al "squadra stabilità", attualmente composta da Greg Kroah-Hartman. affidato al "squadra stabilità", attualmente composta da Greg Kroah-Hartman.
Questa squadra rilascia occasionalmente degli aggiornamenti relativi al Questa squadra rilascia occasionalmente degli aggiornamenti relativi al
rilascio stabile usando la numerazione 4.x.y. Per essere presa in rilascio stabile usando la numerazione 5.x.y. Per essere presa in
considerazione per un rilascio d'aggiornamento, una modifica deve: considerazione per un rilascio d'aggiornamento, una modifica deve:
(1) correggere un baco importante (2) essere già inserita nel ramo principale (1) correggere un baco importante (2) essere già inserita nel ramo principale
per il prossimo sviluppo del kernel. Solitamente, passato il loro rilascio per il prossimo sviluppo del kernel. Solitamente, passato il loro rilascio
iniziale, i kernel ricevono aggiornamenti per più di un ciclo di sviluppo. iniziale, i kernel ricevono aggiornamenti per più di un ciclo di sviluppo.
Quindi, per esempio, la storia del kernel 4.13 appare così: Quindi, per esempio, la storia del kernel 5.2 appare così (anno 2019):
============== =============================== ============== ===============================
Settembre 3 4.13 rilascio stabile 15 settembre 5.2 rilascio stabile FIXME settembre è sbagliato
Settembre 13 4.13.1 14 luglio 5.2.1
Settembre 20 4.13.2 21 luglio 5.2.2
Settembre 27 4.13.3 26 luglio 5.2.3
Ottobre 5 4.13.4 28 luglio 5.2.4
Ottobre 12 4.13.5 31 luglio 5.2.5
... ... ... ...
Novembre 24 4.13.16 11 ottobre 5.2.21
============== =============================== ============== ===============================
La 4.13.16 fu l'aggiornamento finale per la versione 4.13. La 5.2.21 fu l'aggiornamento finale per la versione 5.2.
Alcuni kernel sono destinati ad essere kernel a "lungo termine"; questi Alcuni kernel sono destinati ad essere kernel a "lungo termine"; questi
riceveranno assistenza per un lungo periodo di tempo. Al momento in cui riceveranno assistenza per un lungo periodo di tempo. Al momento in cui
scriviamo, i manutentori dei kernel stabili a lungo termine sono: scriviamo, i manutentori dei kernel stabili a lungo termine sono:
====== ====================== ========================================== ====== ================================ ==========================================
3.16 Ben Hutchings (kernel stabile molto più a lungo termine) 3.16 Ben Hutchings (kernel stabile molto più a lungo termine)
4.1 Sasha Levin 4.4 Greg Kroah-Hartman e Sasha Levin (kernel stabile molto più a lungo termine)
4.4 Greg Kroah-Hartman (kernel stabile molto più a lungo termine) 4.9 Greg Kroah-Hartman e Sasha Levin
4.9 Greg Kroah-Hartman 4.14 Greg Kroah-Hartman e Sasha Levin
4.14 Greg Kroah-Hartman 4.19 Greg Kroah-Hartman e Sasha Levin
====== ====================== ========================================== 5.4i Greg Kroah-Hartman e Sasha Levin
====== ================================ ==========================================
Questa selezione di kernel di lungo periodo sono puramente dovuti ai loro Questa selezione di kernel di lungo periodo sono puramente dovuti ai loro
@ -229,12 +231,13 @@ Come le modifiche finiscono nel Kernel
-------------------------------------- --------------------------------------
Esiste una sola persona che può inserire le patch nel repositorio principale Esiste una sola persona che può inserire le patch nel repositorio principale
del kernel: Linus Torvalds. Ma, di tutte le 9500 patch che entrarono nella del kernel: Linus Torvalds. Ma, per esempio, di tutte le 9500 patch
versione 2.6.38 del kernel, solo 112 (circa l'1,3%) furono scelte direttamente che entrarono nella versione 2.6.38 del kernel, solo 112 (circa
da Linus in persona. Il progetto del kernel è cresciuto fino a raggiungere l'1,3%) furono scelte direttamente da Linus in persona. Il progetto
una dimensione tale per cui un singolo sviluppatore non può controllare e del kernel è cresciuto fino a raggiungere una dimensione tale per cui
selezionare indipendentemente ogni modifica senza essere supportato. un singolo sviluppatore non può controllare e selezionare
La via scelta dagli sviluppatori per indirizzare tale crescita è stata quella indipendentemente ogni modifica senza essere supportato. La via
scelta dagli sviluppatori per indirizzare tale crescita è stata quella
di utilizzare un sistema di "sottotenenti" basato sulla fiducia. di utilizzare un sistema di "sottotenenti" basato sulla fiducia.
Il codice base del kernel è spezzato in una serie si sottosistemi: rete, Il codice base del kernel è spezzato in una serie si sottosistemi: rete,

View File

@ -313,7 +313,7 @@ che conta gli utenti attivi, dovreste chiamarla ``count_active_users()`` o
qualcosa di simile, **non** dovreste chiamarla ``cntusr()``. qualcosa di simile, **non** dovreste chiamarla ``cntusr()``.
Codificare il tipo di funzione nel suo nome (quella cosa chiamata notazione Codificare il tipo di funzione nel suo nome (quella cosa chiamata notazione
ungherese) fa male al cervello - il compilatore conosce comunque il tipo e ungherese) è stupido - il compilatore conosce comunque il tipo e
può verificarli, e inoltre confonde i programmatori. Non c'è da può verificarli, e inoltre confonde i programmatori. Non c'è da
sorprendersi che MicroSoft faccia programmi bacati. sorprendersi che MicroSoft faccia programmi bacati.
@ -825,8 +825,8 @@ linguaggio assembler.
Agli sviluppatori del kernel piace essere visti come dotti. Tenete un occhio Agli sviluppatori del kernel piace essere visti come dotti. Tenete un occhio
di riguardo per l'ortografia e farete una belle figura. In inglese, evitate di riguardo per l'ortografia e farete una belle figura. In inglese, evitate
l'uso di parole mozzate come ``dont``: usate ``do not`` oppure ``don't``. l'uso incorretto di abbreviazioni come ``dont``: usate ``do not`` oppure
Scrivete messaggi concisi, chiari, e inequivocabili. ``don't``. Scrivete messaggi concisi, chiari, e inequivocabili.
I messaggi del kernel non devono terminare con un punto fermo. I messaggi del kernel non devono terminare con un punto fermo.

View File

@ -34,6 +34,33 @@ interfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia
deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne
l'uso. l'uso.
BUG() e BUG_ON()
----------------
Al loro posto usate WARN() e WARN_ON() per gestire le
condizioni "impossibili" e gestitele come se fosse possibile farlo.
Nonostante le funzioni della famiglia BUG() siano state progettate
per asserire "situazioni impossibili" e interrompere in sicurezza un
thread del kernel, queste si sono rivelate essere troppo rischiose
(per esempio, in quale ordine rilasciare i *lock*? Ci sono stati che
sono stati ripristinati?). Molto spesso l'uso di BUG()
destabilizza il sistema o lo corrompe del tutto, il che rende
impossibile un'attività di debug o anche solo leggere un rapporto
circa l'errore. Linus ha un'opinione molto critica al riguardo:
`email 1
<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_,
`email 2
<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_
Tenete presente che la famiglia di funzioni WARN() dovrebbe essere
usato solo per situazioni che si suppone siano "impossibili". Se
volete avvisare gli utenti riguardo a qualcosa di possibile anche se
indesiderato, usare le funzioni della famiglia pr_warn(). Chi
amministra il sistema potrebbe aver attivato l'opzione sysctl
*panic_on_warn* per essere sicuri che il sistema smetta di funzionare
in caso si verifichino delle condizioni "inaspettate". (per esempio,
date un'occhiata al questo `commit
<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_)
Calcoli codificati negli argomenti di un allocatore Calcoli codificati negli argomenti di un allocatore
---------------------------------------------------- ----------------------------------------------------
Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non
@ -68,52 +95,81 @@ Invece, usate la seguente funzione::
header = kzalloc(struct_size(header, item, count), GFP_KERNEL); header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
Per maggiori dettagli fate riferimento a :c:func:`array_size`, Per maggiori dettagli fate riferimento a array_size(),
:c:func:`array3_size`, e :c:func:`struct_size`, così come la famiglia di array3_size(), e struct_size(), così come la famiglia di
funzioni :c:func:`check_add_overflow` e :c:func:`check_mul_overflow`. funzioni check_add_overflow() e check_mul_overflow().
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull() simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
---------------------------------------------------------------------- ----------------------------------------------------------------------
Le funzioni :c:func:`simple_strtol`, :c:func:`simple_strtoll`, Le funzioni simple_strtol(), simple_strtoll(),
:c:func:`simple_strtoul`, e :c:func:`simple_strtoull` ignorano volutamente simple_strtoul(), e simple_strtoull() ignorano volutamente
i possibili overflow, e questo può portare il chiamante a generare risultati i possibili overflow, e questo può portare il chiamante a generare risultati
inaspettati. Le rispettive funzioni :c:func:`kstrtol`, :c:func:`kstrtoll`, inaspettati. Le rispettive funzioni kstrtol(), kstrtoll(),
:c:func:`kstrtoul`, e :c:func:`kstrtoull` sono da considerarsi le corrette kstrtoul(), e kstrtoull() sono da considerarsi le corrette
sostitute; tuttavia va notato che queste richiedono che la stringa sia sostitute; tuttavia va notato che queste richiedono che la stringa sia
terminata con il carattere NUL o quello di nuova riga. terminata con il carattere NUL o quello di nuova riga.
strcpy() strcpy()
-------- --------
La funzione :c:func:`strcpy` non fa controlli agli estremi del buffer La funzione strcpy() non fa controlli agli estremi del buffer
di destinazione. Questo può portare ad un overflow oltre i limiti del di destinazione. Questo può portare ad un overflow oltre i limiti del
buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano `CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
questa funzione. La versione sicura da usare è :c:func:`strscpy`. questa funzione. La versione sicura da usare è strscpy().
strncpy() su stringe terminate con NUL strncpy() su stringe terminate con NUL
-------------------------------------- --------------------------------------
L'utilizzo di :c:func:`strncpy` non fornisce alcuna garanzia sul fatto che L'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che
il buffer di destinazione verrà terminato con il carattere NUL. Questo il buffer di destinazione verrà terminato con il carattere NUL. Questo
potrebbe portare a diversi overflow di lettura o altri malfunzionamenti potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
causati, appunto, dalla mancanza del terminatore. Questa estende la causati, appunto, dalla mancanza del terminatore. Questa estende la
terminazione nel buffer di destinazione quando la stringa d'origine è più terminazione nel buffer di destinazione quando la stringa d'origine è più
corta; questo potrebbe portare ad una penalizzazione delle prestazioni per corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
chi usa solo stringe terminate. La versione sicura da usare è chi usa solo stringe terminate. La versione sicura da usare è
:c:func:`strscpy`. (chi usa :c:func:`strscpy` e necessita di estendere la strscpy(). (chi usa strscpy() e necessita di estendere la
terminazione con NUL deve aggiungere una chiamata a :c:func:`memset`) terminazione con NUL deve aggiungere una chiamata a memset())
Se il chiamate no usa stringhe terminate con NUL, allore :c:func:`strncpy()` Se il chiamate no usa stringhe terminate con NUL, allore strncpy()()
può continuare ad essere usata, ma i buffer di destinazione devono essere può continuare ad essere usata, ma i buffer di destinazione devono essere
marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_ marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
per evitare avvisi durante la compilazione. per evitare avvisi durante la compilazione.
strlcpy() strlcpy()
--------- ---------
La funzione :c:func:`strlcpy`, per prima cosa, legge interamente il buffer di La funzione strlcpy(), per prima cosa, legge interamente il buffer di
origine, magari leggendo più di quanto verrà effettivamente copiato. Questo origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
è inefficiente e può portare a overflow di lettura quando la stringa non è è inefficiente e può portare a overflow di lettura quando la stringa non è
terminata con NUL. La versione sicura da usare è :c:func:`strscpy`. terminata con NUL. La versione sicura da usare è strscpy().
Segnaposto %p nella stringa di formato
--------------------------------------
Tradizionalmente, l'uso del segnaposto "%p" nella stringa di formato
esponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera. Per
evitare che questi indirizzi vengano sfruttati da malintenzionati,
tutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo,
rendendolo di fatto inutilizzabile. Nuovi usi di "%p" non dovrebbero
essere aggiunti al kernel. Per una rappresentazione testuale di un
indirizzo usate "%pS", l'output è migliore perché mostrerà il nome del
simbolo. Per tutto il resto, semplicemente non usate "%p".
Parafrasando la `guida
<https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_
di Linus:
- Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso
è importante. Forse dovrebbe essere rimosso del tutto?
- Se credi davvero che il vero valore del puntatore sia importante,
perché alcuni stati del sistema o i livelli di privilegi di un
utente sono considerati "special"? Se pensi di poterlo giustificare
(in un commento e nel messaggio del commit) abbastanza bene da
affrontare il giudizio di Linus, allora forse potrai usare "%px",
assicurandosi anche di averne il permesso.
Infine, sappi che un cambio in favore di "%p" con hash `non verrà
accettato
<https://lore.kernel.org/lkml/CA+55aFwieC1-nAs+NFq9RTwaR8ef9hWa4MjNBWL41F-8wM49eA@mail.gmail.com/>`_.
Vettori a dimensione variabile (VLA) Vettori a dimensione variabile (VLA)
------------------------------------ ------------------------------------
@ -127,3 +183,47 @@ Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere
dati importanti alla fine dello stack (quando il kernel è compilato senza dati importanti alla fine dello stack (quando il kernel è compilato senza
`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente `CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`). allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
Salto implicito nell'istruzione switch-case
-------------------------------------------
Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al
prossimo caso quando l'istruzione "break" viene omessa alla fine del caso
corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se
l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio,
osservando il seguente pezzo di codice non è chiaro se lo stato
`STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`::
switch (value) {
case STATE_ONE:
do_something();
case STATE_TWO:
do_other();
break;
default:
WARN("unknown state");
}
Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione
"break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non
permettiamo più che vi sia un "salto implicito" (*fall-through*). Per
identificare un salto implicito intenzionale abbiamo adottato la pseudo
parola chiave 'fallthrough' che viene espansa nell'estensione di gcc
`__attribute__((fallthrough))` `Statement Attributes
<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
(Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente
supportata dai compilatori C, analizzatori statici, e dagli IDE,
allora potremo usare quella sintassi per la pseudo parola chiave)
Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai
compilatori, analizzatori statici, e ambienti di sviluppo IDE,
allora potremo usarla anche noi.
Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti
modi:
* ``break;``
* `fallthrough;``
* ``continue;``
* ``goto <label>;``
* ``return [expression];``