[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240130202340.tmppiux5oiwvrtij@numero-86.vaga.pv.it>
Date: Tue, 30 Jan 2024 21:23:40 +0100
From: Federico Vaga <federico.vaga@...a.pv.it>
To: Jonathan Corbet <corbet@....net>
Cc: linux-doc@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH] doc:it_IT: first translation for locking/
Hi Jon,
I hope you are doing well. I do not want to disturbe you too much, I'm pinging
you just in case this patch got lost.
On Sun, Jan 07, 2024 at 12:38:20AM +0100, Federico Vaga wrote:
>To begin with:
> - locking/index.rst
> - locking/lockdep-design.rst
> - locking/lockstat.rst
> - locking/lockturture.rst
> - locking/locktypes.rst
>
>And RCU/torture.rst to avoid broken references.
>
>Signed-off-by: Federico Vaga <federico.vaga@...a.pv.it>
>---
> Documentation/RCU/torture.rst | 2 +-
> .../translations/it_IT/RCU/index.rst | 19 +
> .../translations/it_IT/RCU/torture.rst | 369 ++++++++++
> .../translations/it_IT/core-api/index.rst | 12 +
> Documentation/translations/it_IT/index.rst | 1 +
> .../translations/it_IT/locking/index.rst | 20 +
> .../it_IT/locking/lockdep-design.rst | 678 ++++++++++++++++++
> .../translations/it_IT/locking/lockstat.rst | 230 ++++++
> .../it_IT/locking/locktorture.rst | 181 +++++
> .../translations/it_IT/locking/locktypes.rst | 547 ++++++++++++++
> 10 files changed, 2058 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/translations/it_IT/RCU/index.rst
> create mode 100644 Documentation/translations/it_IT/RCU/torture.rst
> create mode 100644 Documentation/translations/it_IT/locking/index.rst
> create mode 100644 Documentation/translations/it_IT/locking/lockdep-design.rst
> create mode 100644 Documentation/translations/it_IT/locking/lockstat.rst
> create mode 100644 Documentation/translations/it_IT/locking/locktorture.rst
> create mode 100644 Documentation/translations/it_IT/locking/locktypes.rst
>
>diff --git a/Documentation/RCU/torture.rst b/Documentation/RCU/torture.rst
>index b3b6dfa85248..f04730366069 100644
>--- a/Documentation/RCU/torture.rst
>+++ b/Documentation/RCU/torture.rst
>@@ -318,7 +318,7 @@ Suppose that a previous kvm.sh run left its output in this directory::
>
> tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28
>
>-Then this run can be re-run without rebuilding as follow:
>+Then this run can be re-run without rebuilding as follow::
>
> kvm-again.sh tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28
>
>diff --git a/Documentation/translations/it_IT/RCU/index.rst b/Documentation/translations/it_IT/RCU/index.rst
>new file mode 100644
>index 000000000000..22adf1d58752
>--- /dev/null
>+++ b/Documentation/translations/it_IT/RCU/index.rst
>@@ -0,0 +1,19 @@
>+.. SPDX-License-Identifier: GPL-2.0
>+
>+.. _it_rcu_concepts:
>+
>+===============
>+Concetti su RCU
>+===============
>+
>+.. toctree::
>+ :maxdepth: 3
>+
>+ torture
>+
>+.. only:: subproject and html
>+
>+ Indici
>+ ======
>+
>+ * :ref:`genindex`
>diff --git a/Documentation/translations/it_IT/RCU/torture.rst b/Documentation/translations/it_IT/RCU/torture.rst
>new file mode 100644
>index 000000000000..79d9e6932acc
>--- /dev/null
>+++ b/Documentation/translations/it_IT/RCU/torture.rst
>@@ -0,0 +1,369 @@
>+.. SPDX-License-Identifier: GPL-2.0
>+
>+.. include:: ../disclaimer-ita.rst
>+
>+=============================================
>+Le operazioni RCU per le verifiche *torture*
>+=============================================
>+
>+CONFIG_RCU_TORTURE_TEST
>+=======================
>+
>+L'opzione CONFIG_RCU_TORTURE_TEST è disponibile per tutte le implementazione di
>+RCU. L'opzione creerà un modulo rcutorture che potrete caricare per avviare le
>+verifiche. La verifica userà printk() per riportare lo stato, dunque potrete
>+visualizzarlo con dmesg (magari usate grep per filtrare "torture"). Le verifiche
>+inizieranno al caricamento, e si fermeranno alla sua rimozione.
>+
>+I parametri di modulo hanno tutti il prefisso "rcutortute.", vedere
>+Documentation/admin-guide/kernel-parameters.txt.
>+
>+Rapporto
>+========
>+
>+Il rapporto sulle verifiche si presenta nel seguente modo::
>+
>+ rcu-torture:--- Start of test: nreaders=16 nfakewriters=4 stat_interval=30 verbose=0 test_no_idle_hz=1 shuffle_interval=3 stutter=5 irqreader=1 fqs_duration=0 fqs_holdoff=0 fqs_stutter=3 test_boost=1/0 test_boost_interval=7 test_boost_duration=4
>+ rcu-torture: rtc: (null) ver: 155441 tfle: 0 rta: 155441 rtaf: 8884 rtf: 155440 rtmbe: 0 rtbe: 0 rtbke: 0 rtbre: 0 rtbf: 0 rtb: 0 nt: 3055767
>+ rcu-torture: Reader Pipe: 727860534 34213 0 0 0 0 0 0 0 0 0
>+ rcu-torture: Reader Batch: 727877838 17003 0 0 0 0 0 0 0 0 0
>+ rcu-torture: Free-Block Circulation: 155440 155440 155440 155440 155440 155440 155440 155440 155440 155440 0
>+ rcu-torture:--- End of test: SUCCESS: nreaders=16 nfakewriters=4 stat_interval=30 verbose=0 test_no_idle_hz=1 shuffle_interval=3 stutter=5 irqreader=1 fqs_duration=0 fqs_holdoff=0 fqs_stutter=3 test_boost=1/0 test_boost_interval=7 test_boost_duration=4
>+
>+Sulla maggior parte dei sistemi questo rapporto si produce col comando "dmesg |
>+grep torture:". Su configurazioni più esoteriche potrebbe essere necessario
>+usare altri comandi per visualizzare i messaggi di printk(). La funzione
>+printk() usa KERN_ALERT, dunque i messaggi dovrebbero essere ben visibili. ;-)
>+
>+La prima e l'ultima riga mostrano i parametri di module di rcutorture, e solo
>+sull'ultima riga abbiamo il risultato finale delle verifiche effettuate che può
>+essere "SUCCESS" (successo) or "FAILURE" (insuccesso).
>+
>+Le voci sono le seguenti:
>+
>+* "rtc": L'indirizzo in esadecimale della struttura attualmente visibile dai
>+ lettori.
>+
>+* "ver": Il numero di volte dall'avvio che il processo scrittore di RCU ha
>+ cambiato la struttura visible ai lettori.
>+
>+* "tfle": se non è zero, indica la lista di strutture "torture freelist" da
>+ mettere in "rtc" è vuota. Questa condizione è importante perché potrebbe
>+ illuderti che RCU stia funzionando mentre invece non è il caso. :-/
>+
>+* "rta": numero di strutture allocate dalla lista "torture freelist".
>+
>+* "rtaf": il numero di allocazioni fallite dalla lista "torture freelist" a
>+ causa del fatto che fosse vuota. Non è inusuale che sia diverso da zero, ma è
>+ un brutto segno se questo numero rappresenta una frazione troppo alta di
>+ "rta".
>+
>+* "rtf": il numero di rilasci nella lista "torture freelist"
>+
>+* "rtmbe": Un valore diverso da zero indica che rcutorture crede che
>+ rcu_assign_pointer() e rcu_dereference() non funzionino correttamente. Il
>+ valore dovrebbe essere zero.
>+
>+* "rtbe": un valore diverso da zero indica che le funzioni della famiglia
>+ rcu_barrier() non funzionano correttamente.
>+
>+* "rtbke": rcutorture è stato capace di creare dei kthread real-time per forzare
>+ l'inversione di priorità di RCU. Il valore dovrebbe essere zero.
>+
>+* "rtbre": sebbene rcutorture sia riuscito a creare dei kthread capaci di
>+ forzare l'inversione di priorità, non è riuscito però ad impostarne la
>+ priorità real-time al livello 1. Il valore dovrebbe essere zero.
>+
>+* "rtbf": Il numero di volte che è fallita la promozione della priorità per
>+ risolvere un'inversione.
>+
>+* "rtb": Il numero di volte che rcutorture ha provato a forzare l'inversione di
>+ priorità. Il valore dovrebbe essere diverso da zero Se state verificando la
>+ promozione della priorità col parametro "test_bootst".
>+
>+* "nt": il numero di volte che rcutorture ha eseguito codice lato lettura
>+ all'interno di un gestore di *timer*. Questo valore dovrebbe essere diverso da
>+ zero se avete specificato il parametro "irqreader".
>+
>+* "Reader Pipe": un istogramma dell'età delle strutture viste dai lettori. RCU
>+ non funziona correttamente se una qualunque voce, dalla terza in poi, ha un
>+ valore diverso da zero. Se dovesse succedere, rcutorture stampa la stringa
>+ "!!!" per renderlo ben visibile. L'età di una struttura appena creata è zero,
>+ diventerà uno quando sparisce dalla visibilità di un lettore, e incrementata
>+ successivamente per ogni periodo di grazia; infine rilasciata dopo essere
>+ passata per (RCU_TORTURE_PIPE_LEN-2) periodi di grazia.
>+
>+ L'istantanea qui sopra è stata presa da una corretta implementazione di RCU.
>+ Se volete vedere come appare quando non funziona, sbizzarritevi nel romperla.
>+ ;-)
>+
>+* "Reader Batch": un istogramma di età di strutture viste dai lettori, ma
>+ conteggiata in termini di lotti piuttosto che periodi. Anche qui dalla terza
>+ voce in poi devono essere zero. La ragione d'esistere di questo rapporto è che
>+ a volte è più facile scatenare un terzo valore diverso da zero qui piuttosto
>+ che nella lista "Reader Pipe".
>+
>+* "Free-Block Circulation": il numero di strutture *torture* che hanno raggiunto
>+ un certo punto nella catena. Il primo numero dovrebbe corrispondere
>+ strettamente al numero di strutture allocate; il secondo conta quelle rimosse
>+ dalla vista dei lettori. Ad eccezione dell'ultimo valore, gli altri
>+ corrispondono al numero di passaggi attraverso il periodo di grazia. L'ultimo
>+ valore dovrebbe essere zero, perché viene incrementato solo se il contatore
>+ della struttura torture viene in un qualche modo incrementato oltre il
>+ normale.
>+
>+Una diversa implementazione di RCU potrebbe fornire informazioni aggiuntive. Per
>+esempio, *Tree SRCU* fornisce anche la seguente riga::
>+
>+ srcud-torture: Tree SRCU per-CPU(idx=0): 0(35,-21) 1(-4,24) 2(1,1) 3(-26,20) 4(28,-47) 5(-9,4) 6(-10,14) 7(-14,11) T(1,6)
>+
>+Questa riga mostra lo stato dei contatori per processore, in questo caso per
>+*Tree SRCU*, usando un'allocazione dinamica di srcu_struct (dunque "srcud-"
>+piuttosto che "srcu-"). I numeri fra parentesi sono i valori del "vecchio"
>+contatore e di quello "corrente" per ogni processore. Il valore "idx" mappa
>+questi due valori nell'array, ed è utile per il *debug*. La "T" finale contiene
>+il valore totale dei contatori.
>+
>+Uso su specifici kernel
>+=======================
>+
>+A volte può essere utile eseguire RCU torture su un kernel già compilato, ad
>+esempio quando lo si sta per mettere in proeduzione. In questo caso, il kernel
>+dev'essere compilato con CONFIG_RCU_TORTUE_TEST=m, cosicché le verifiche possano
>+essere avviate usano modprobe e terminate con rmmod.
>+
>+Per esempio, potreste usare questo script::
>+
>+ #!/bin/sh
>+
>+ modprobe rcutorture
>+ sleep 3600
>+ rmmod rcutorture
>+ dmesg | grep torture:
>+
>+Potete controllare il rapporto verificando manualmente la presenza del marcatore
>+di errore "!!!". Ovviamente, siete liberi di scriverne uno più elaborato che
>+identifichi automaticamente gli errori. Il comando "rmmod" forza la stampa di
>+"SUCCESS" (successo), "FAILURE" (fallimento), o "RCU_HOTPLUG". I primi due sono
>+autoesplicativi; invece, l'ultimo indica che non son stati trovati problemi in
>+RCU, tuttavia ci sono stati problemi con CPU-hotplug.
>+
>+
>+Uso sul kernel di riferimento
>+=============================
>+
>+Quando si usa rcutorture per verificare modifiche ad RCU stesso, spesso è
>+necessario compilare un certo numero di kernel usando configurazioni diverse e
>+con parametri d'avvio diversi. In questi casi, usare modprobe ed rmmod potrebbe
>+richiedere molto tempo ed il processo essere suscettibile ad errori.
>+
>+Dunque, viene messo a disposizione il programma
>+tools/testing/selftests/rcutorture/bin/kvm.sh per le architetture x86, arm64 e
>+powerpc. Di base, eseguirà la serie di verifiche elencate in
>+tools/testing/selftests/rcutorture/configs/rcu/CFLIST. Ognuna di queste verrà
>+eseguita per 30 minuti in una macchina virtuale con uno spazio utente minimale
>+fornito da un initrd generato automaticamente. Al completamento, gli artefatti
>+prodotti e i messaggi vengono analizzati alla ricerca di errori, ed i risultati
>+delle esecuzioni riassunti in un rapporto.
>+
>+Su grandi sistemi, le verifiche di rcutorture posso essere velocizzare passano a
>+kvm.sh l'argomento --cpus. Per esempio, su un sistema a 64 processori, "--cpus
>+43" userà fino a 43 processori per eseguire contemporaneamente le verifiche. Su
>+un kernel v5.4 per eseguire tutti gli scenari in due serie, riduce il tempo
>+d'esecuzione da otto ore a un'ora (senza contare il tempo per compilare sedici
>+kernel). L'argomento "--dryrun sched" non eseguirà verifiche, piuttosto vi
>+informerà su come queste verranno organizzate in serie. Questo può essere utile
>+per capire quanti processori riservare per le verifiche in --cpus.
>+
>+Non serve eseguire tutti gli scenari di verifica per ogni modifica. Per esempio,
>+per una modifica a Tree SRCU potete eseguire gli scenari SRCU-N e SRCU-P. Per
>+farlo usate l'argomento --configs di kvm.sh in questo modo: "--configs 'SRCU-N
>+SRCU-P'". Su grandi sistemi si possono eseguire più copie degli stessi scenari,
>+per esempio, un hardware che permette di eseguire 448 thread, può eseguire 5
>+istanze complete contemporaneamente. Per farlo::
>+
>+ kvm.sh --cpus 448 --configs '5*CFLIST'
>+
>+Oppure, lo stesso sistema, può eseguire contemporaneamente 56 istanze dello
>+scenario su otto processori::
>+
>+ kvm.sh --cpus 448 --configs '56*TREE04'
>+
>+O ancora 28 istanze per ogni scenario su otto processori::
>+
>+ kvm.sh --cpus 448 --configs '28*TREE03 28*TREE04'
>+
>+Ovviamente, ogni esecuzione utilizzerà della memoria. Potete limitarne l'uso con
>+l'argomento --memory, che di base assume il valore 512M. Per poter usare valori
>+piccoli dovrete disabilitare le verifiche *callback-flooding* usando il
>+parametro --bootargs che vedremo in seguito.
>+
>+A volte è utile avere informazioni aggiuntive di debug, in questo caso potete
>+usare il parametro --kconfig, per esempio, ``--kconfig
>+'CONFIG_RCU_EQS_DEBUG=y'``. In aggiunta, ci sono i parametri --gdb, --kasan, and
>+kcsan. Da notare che --gdb vi limiterà all'uso di un solo scenario per
>+esecuzione di kvm.sh e richiede di avere anche un'altra finestra aperta dalla
>+quale eseguire ``gdb`` come viene spiegato dal programma.
>+
>+Potete passare anche i parametri d'avvio del kernel, per esempio, per
>+controllare i parametri del modulo rcutorture. Per esempio, per verificare
>+modifiche del codice RCU CPU stall-warning, usate ``bootargs
>+'rcutorture.stall_cpu=30``. Il programma riporterà un fallimento, ossia il
>+risultato della verifica. Come visto in precedenza, ridurre la memoria richiede
>+la disabilitazione delle verifiche *callback-flooding*::
>+
>+ kvm.sh --cpus 448 --configs '56*TREE04' --memory 128M \
>+ --bootargs 'rcutorture.fwd_progress=0'
>+
>+A volte tutto quello che serve è una serie completa di compilazioni del kernel.
>+Questo si ottiene col parametro --buildonly.
>+
>+Il parametro --duration sovrascrive quello di base di 30 minuti. Per esempio,
>+con ``--duration 2d`` l'esecuzione sarà di due giorni, ``--duraction 5min`` di
>+cinque minuti, e ``--duration 45s`` di 45 secondi. L'ultimo può essere utile per
>+scovare rari errori nella sequenza d'avvio.
>+
>+Infine, il parametro --trust-make permette ad ogni nuova compilazione del kernel
>+di riutilizzare tutto il possibile da quelle precedenti. Da notare che senza il
>+parametro --trust-make, i vostri file di *tag* potrebbero essere distrutti.
>+
>+Ci sono altri parametri più misteriosi che sono documentati nel codice sorgente
>+dello programma kvm.sh.
>+
>+Se un'esecuzione contiene degli errori, il loro numero durante la compilazione e
>+all'esecuzione verranno elencati alla fine fra i risultati di kvm.sh (che vi
>+consigliamo caldamente di reindirizzare verso un file). I file prodotti dalla
>+compilazione ed i risultati stampati vengono salvati, usando un riferimento
>+temporale, nelle cartella tools/testing/selftests/rcutorture/res. Una cartella
>+di queste cartelle può essere fornita a kvm-find-errors.sh per estrarne gli
>+errori. Per esempio::
>+
>+ tools/testing/selftests/rcutorture/bin/kvm-find-errors.sh \
>+ tools/testing/selftests/rcutorture/res/2020.01.20-15.54.23
>+
>+Tuttavia, molto spesso è più conveniente aprire i file direttamente. I file
>+riguardanti tutti gli scenari di un'esecuzione di trovano nella cartella
>+principale (2020.01.20-15.54.23 nell'esempio precedente), mentre quelli
>+specifici per scenario si trovano in sotto cartelle che prendono il nome dello
>+scenario stesso (per esempio, "TREE04"). Se un dato scenario viene eseguito più
>+di una volta (come abbiamo visto con "--configs '56*TREE04'"), allora dalla
>+seconda esecuzione in poi le sottocartelle includeranno un numero di
>+progressione, per esempio "TREE04.2", "TREE04.3", e via dicendo.
>+
>+Il file solitamente più usato nella cartella principale è testid.txt. Se la
>+verifica viene eseguita in un repositorio git, allora questo file conterrà il
>+*commit* sul quale si basano le verifiche, mentre tutte le modifiche non
>+registrare verranno mostrate in formato diff.
>+
>+I file solitamente più usati nelle cartelle di scenario sono:
>+
>+.config
>+ Questo file contiene le opzioni di Kconfig
>+
>+Make.out
>+ Questo file contiene il risultato di compilazione per uno specifico scenario
>+
>+console.log
>+ Questo file contiene il risultato d'esecuzione per uno specifico scenario.
>+ Questo file può essere esaminato una volta che il kernel è stato avviato,
>+ ma potrebbe non esistere se l'avvia non è fallito.
>+
>+vmlinux
>+ Questo file contiene il kernel, e potrebbe essere utile da esaminare con
>+ programmi come pbjdump e gdb
>+
>+Ci sono altri file, ma vengono usati meno. Molti sono utili all'analisi di
>+rcutorture stesso o dei suoi programmi.
>+
>+Nel kernel v5.4, su un sistema a 12 processori, un'esecuzione senza errori
>+usando gli scenari di base produce il seguente risultato::
>+
>+ SRCU-N ------- 804233 GPs (148.932/s) [srcu: g10008272 f0x0 ]
>+ SRCU-P ------- 202320 GPs (37.4667/s) [srcud: g1809476 f0x0 ]
>+ SRCU-t ------- 1122086 GPs (207.794/s) [srcu: g0 f0x0 ]
>+ SRCU-u ------- 1111285 GPs (205.794/s) [srcud: g1 f0x0 ]
>+ TASKS01 ------- 19666 GPs (3.64185/s) [tasks: g0 f0x0 ]
>+ TASKS02 ------- 20541 GPs (3.80389/s) [tasks: g0 f0x0 ]
>+ TASKS03 ------- 19416 GPs (3.59556/s) [tasks: g0 f0x0 ]
>+ TINY01 ------- 836134 GPs (154.84/s) [rcu: g0 f0x0 ] n_max_cbs: 34198
>+ TINY02 ------- 850371 GPs (157.476/s) [rcu: g0 f0x0 ] n_max_cbs: 2631
>+ TREE01 ------- 162625 GPs (30.1157/s) [rcu: g1124169 f0x0 ]
>+ TREE02 ------- 333003 GPs (61.6672/s) [rcu: g2647753 f0x0 ] n_max_cbs: 35844
>+ TREE03 ------- 306623 GPs (56.782/s) [rcu: g2975325 f0x0 ] n_max_cbs: 1496497
>+ CPU count limited from 16 to 12
>+ TREE04 ------- 246149 GPs (45.5831/s) [rcu: g1695737 f0x0 ] n_max_cbs: 434961
>+ TREE05 ------- 314603 GPs (58.2598/s) [rcu: g2257741 f0x2 ] n_max_cbs: 193997
>+ TREE07 ------- 167347 GPs (30.9902/s) [rcu: g1079021 f0x0 ] n_max_cbs: 478732
>+ CPU count limited from 16 to 12
>+ TREE09 ------- 752238 GPs (139.303/s) [rcu: g13075057 f0x0 ] n_max_cbs: 99011
>+
>+Ripetizioni
>+===========
>+
>+Immaginate di essere alla caccia di un raro problema che si verifica all'avvio.
>+Potreste usare kvm.sh, tuttavia questo ricompilerebbe il kernel ad ogni
>+esecuzione. Se avete bisogno di (diciamo) 1000 esecuzioni per essere sicuri di
>+aver risolto il problema, allora queste inutili ricompilazioni possono diventare
>+estremamente fastidiose.
>+
>+Per questo motivo esiste kvm-again.sh.
>+
>+Immaginate che un'esecuzione precedente di kvm.sh abbia lasciato i suoi
>+artefatti nella cartella::
>+
>+ tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28
>+
>+Questa esecuzione può essere rieseguita senza ricompilazioni::
>+
>+ kvm-again.sh tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28
>+
>+Alcuni dei parametri originali di kvm.sh possono essere sovrascritti, in
>+particolare --duration e --bootargs. Per esempio::
>+
>+ kvm-again.sh tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28 \
>+ --duration 45s
>+
>+rieseguirebbe il test precedente, ma solo per 45 secondi, e quindi aiutando a
>+trovare quel raro problema all'avvio sopracitato.
>+
>+Esecuzioni distribuite
>+======================
>+
>+Sebbene kvm.sh sia utile, le sue verifiche sono limitate ad un singolo sistema.
>+Non è poi così difficile usare un qualsiasi ambiente di sviluppo per eseguire
>+(diciamo) 5 istanze di kvm.sh su altrettanti sistemi, ma questo avvierebbe
>+inutili ricompilazioni del kernel. In aggiunta, il processo di distribuzione
>+degli scenari di verifica per rcutorture sui sistemi disponibili richiede
>+scrupolo perché soggetto ad errori.
>+
>+Per questo esiste kvm-remote.sh.
>+
>+Se il seguente comando funziona::
>+
>+ ssh system0 date
>+
>+e funziona anche per system1, system2, system3, system4, e system5, e tutti
>+questi sistemi hanno 64 CPU, allora potere eseguire::
>+
>+ kvm-remote.sh "system0 system1 system2 system3 system4 system5" \
>+ --cpus 64 --duration 8h --configs "5*CFLIST"
>+
>+Questo compilerà lo scenario di base sul sistema locale, poi lo distribuirà agli
>+altri cinque sistemi elencati fra i parametri, ed eseguirà ogni scenario per
>+otto ore. Alla fine delle esecuzioni, i risultati verranno raccolti, registrati,
>+e stampati. La maggior parte dei parametri di kvm.sh possono essere usati con
>+kvm-remote.sh, tuttavia la lista dei sistemi deve venire sempre per prima.
>+
>+L'argomento di kvm.sh ``--dryrun scenarios`` può essere utile per scoprire
>+quanti scenari potrebbero essere eseguiti in gruppo di sistemi.
>+
>+Potete rieseguire anche una precedente esecuzione remota come abbiamo già fatto
>+per kvm.sh::
>+
>+ kvm-remote.sh "system0 system1 system2 system3 system4 system5" \
>+ tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28-remote \
>+ --duration 24h
>+
>+In questo caso, la maggior parte dei parametri di kvm-again.sh possono essere
>+usati dopo il percorso alla cartella contenente gli artefatti dell'esecuzione da
>+ripetere.
>diff --git a/Documentation/translations/it_IT/core-api/index.rst b/Documentation/translations/it_IT/core-api/index.rst
>index cc4c4328ad03..dad20402d11b 100644
>--- a/Documentation/translations/it_IT/core-api/index.rst
>+++ b/Documentation/translations/it_IT/core-api/index.rst
>@@ -10,6 +10,18 @@ Utilità di base
>
> symbol-namespaces
>
>+Primitive di sincronizzazione
>+=============================
>+
>+Come Linux impedisce che tutto si verifichi contemporaneamente. Consultate
>+Documentation/translations/it_IT/locking/index.rst per maggiorni informazioni
>+sul tema.
>+
>+.. toctree::
>+ :maxdepth: 1
>+
>+ ../RCU/index
>+
> .. only:: subproject and html
>
> Indices
>diff --git a/Documentation/translations/it_IT/index.rst b/Documentation/translations/it_IT/index.rst
>index b95dfa1ded04..51a15bf37577 100644
>--- a/Documentation/translations/it_IT/index.rst
>+++ b/Documentation/translations/it_IT/index.rst
>@@ -91,6 +91,7 @@ interfacciarsi con il resto del kernel.
> :maxdepth: 1
>
> core-api/index
>+ Sincronizzazione nel kernel <locking/index>
>
> Strumenti e processi per lo sviluppo
> ====================================
>diff --git a/Documentation/translations/it_IT/locking/index.rst b/Documentation/translations/it_IT/locking/index.rst
>new file mode 100644
>index 000000000000..19963d33e84d
>--- /dev/null
>+++ b/Documentation/translations/it_IT/locking/index.rst
>@@ -0,0 +1,20 @@
>+.. SPDX-License-Identifier: GPL-2.0
>+
>+================
>+Sincronizzazione
>+================
>+
>+.. toctree::
>+ :maxdepth: 1
>+
>+ locktypes
>+ lockdep-design
>+ lockstat
>+ locktorture
>+
>+.. only:: subproject and html
>+
>+ Indici
>+ ======
>+
>+ * :ref:`genindex`
>diff --git a/Documentation/translations/it_IT/locking/lockdep-design.rst b/Documentation/translations/it_IT/locking/lockdep-design.rst
>new file mode 100644
>index 000000000000..9ed00d8cf280
>--- /dev/null
>+++ b/Documentation/translations/it_IT/locking/lockdep-design.rst
>@@ -0,0 +1,678 @@
>+.. SPDX-License-Identifier: GPL-2.0
>+
>+.. include:: ../disclaimer-ita.rst
>+
>+Validatore di sincronizzazione durante l'esecuzione
>+===================================================
>+
>+Classi di blocchi
>+-----------------
>+
>+L'oggetto su cui il validatore lavora è una "classe" di blocchi.
>+
>+Una classe di blocchi è un gruppo di blocchi che seguono le stesse regole di
>+sincronizzazione, anche quando i blocchi potrebbero avere più istanze (anche
>+decine di migliaia). Per esempio un blocco nella struttura inode è una classe,
>+mentre ogni inode sarà un'istanza di questa classe di blocco.
>+
>+Il validatore traccia lo "stato d'uso" di una classe di blocchi e le sue
>+dipendenze con altre classi. L'uso di un blocco indica come quel blocco viene
>+usato rispetto al suo contesto d'interruzione, mentre le dipendenze di un blocco
>+possono essere interpretate come il loro ordine; per esempio L1 -> L2 suggerisce
>+che un processo cerca di acquisire L2 mentre già trattiene L1. Dal punto di
>+vista di lockdep, i due blocchi (L1 ed L2) non sono per forza correlati: quella
>+dipendenza indica solamente l'ordine in cui sono successe le cose. Il validatore
>+verifica permanentemente la correttezza dell'uso dei blocchi e delle loro
>+dipendenze, altrimenti ritornerà un errore.
>+
>+Il comportamento di una classe di blocchi viene costruito dall'insieme delle sue
>+istanze. Una classe di blocco viene registrata alla creazione della sua prima
>+istanza, mentre tutte le successive istanze verranno mappate; dunque, il loro
>+uso e le loro dipendenze contribuiranno a costruire quello della classe. Una
>+classe di blocco non sparisce quando sparisce una sua istanza, ma può essere
>+rimossa quando il suo spazio in memoria viene reclamato. Per esempio, questo
>+succede quando si rimuove un modulo, o quando una *workqueue* viene eliminata.
>+
>+Stato
>+-----
>+
>+Il validatore traccia l'uso cronologico delle classi di blocchi e ne divide
>+l'uso in categorie (4 USI * n STATI + 1).
>+
>+I quattro USI possono essere:
>+
>+- 'sempre trattenuto nel contesto <STATO>'
>+- 'sempre trattenuto come blocco di lettura nel contesto <STATO>'
>+- 'sempre trattenuto con <STATO> abilitato'
>+- 'sempre trattenuto come blocco di lettura con <STATO> abilitato'
>+
>+gli `n` STATI sono codificati in kernel/locking/lockdep_states.h, ad oggi
>+includono:
>+
>+- hardirq
>+- softirq
>+
>+infine l'ultima categoria è:
>+
>+- 'sempre trattenuto' [ == !unused ]
>+
>+Quando vengono violate le regole di sincronizzazione, questi bit di utilizzo
>+vengono presentati nei messaggi di errore di sincronizzazione, fra parentesi
>+graffe, per un totale di `2 * n` (`n`: bit STATO). Un esempio inventato::
>+
>+ modprobe/2287 is trying to acquire lock:
>+ (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
>+
>+ but task is already holding lock:
>+ (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
>+
>+Per un dato blocco, da sinistra verso destra, la posizione del bit indica l'uso
>+del blocco e di un eventuale blocco di lettura, per ognuno degli `n` STATI elencati
>+precedentemente. Il carattere mostrato per ogni bit indica:
>+
>+ === ===========================================================================
>+ '.' acquisito con interruzioni disabilitate fuori da un contesto d'interruzione
>+ '-' acquisito in contesto d'interruzione
>+ '+' acquisito con interruzioni abilitate
>+ '?' acquisito in contesto d'interruzione con interruzioni abilitate
>+ === ===========================================================================
>+
>+Il seguente esempio mostra i bit::
>+
>+ (&sio_locks[i].lock){-.-.}, at: [<c02867fd>] mutex_lock+0x21/0x24
>+ ||||
>+ ||| \-> softirq disabilitati e fuori da un contesto di softirq
>+ || \--> acquisito in un contesto di softirq
>+ | \---> hardirq disabilitati e fuori da un contesto di hardirq
>+ \----> acquisito in un contesto di hardirq
>+
>+Per un dato STATO, che il blocco sia mai stato acquisito in quel contesto di
>+STATO, o che lo STATO sia abilitato, ci lascia coi quattro possibili scenari
>+mostrati nella seguente tabella. Il carattere associato al bit indica con
>+esattezza in quale scenario ci si trova al momento del rapporto.
>+
>+ +---------------+---------------+------------------+
>+ | | irq abilitati | irq disabilitati |
>+ +---------------+---------------+------------------+
>+ | sempre in irq | '?' | '-' |
>+ +---------------+---------------+------------------+
>+ | mai in irq | '+' | '.' |
>+ +---------------+---------------+------------------+
>+
>+Il carattere '-' suggerisce che le interruzioni sono disabilitate perché
>+altrimenti verrebbe mostrato il carattere '?'. Una deduzione simile può essere
>+fatta anche per '+'
>+
>+I blocchi inutilizzati (ad esempio i mutex) non possono essere fra le cause di
>+un errore.
>+
>+Regole dello stato per un blocco singolo
>+----------------------------------------
>+
>+Avere un blocco sicuro in interruzioni (*irq-safe*) significa che è sempre stato
>+usato in un contesto d'interruzione, mentre un blocco insicuro in interruzioni
>+(*irq-unsafe*) significa che è sempre stato acquisito con le interruzioni
>+abilitate.
>+
>+Una classe softirq insicura è automaticamente insicura anche per hardirq. I
>+seguenti stati sono mutualmente esclusivi: solo una può essere vero quando viene
>+usata una classe di blocco::
>+
>+ <hardirq-safe> o <hardirq-unsafe>
>+ <softirq-safe> o <softirq-unsafe>
>+
>+Questo perché se un blocco può essere usato in un contesto di interruzioni
>+(sicuro in interruzioni), allora non può mai essere acquisito con le
>+interruzioni abilitate (insicuro in interruzioni). Altrimenti potrebbe
>+verificarsi uno stallo. Per esempio, questo blocco viene acquisito, ma prima di
>+essere rilasciato il contesto d'esecuzione viene interrotto nuovamente, e quindi
>+si tenterà di acquisirlo nuovamente. Questo porterà ad uno stallo, in
>+particolare uno stallo ricorsivo.
>+
>+Il validatore rileva e riporta gli usi di blocchi che violano queste regole per
>+blocchi singoli.
>+
>+Regole per le dipendenze di blocchi multipli
>+--------------------------------------------
>+
>+La stessa classe di blocco non deve essere acquisita due volte, questo perché
>+potrebbe portare ad uno blocco ricorsivo e dunque ad uno stallo.
>+
>+Inoltre, due blocchi non possono essere trattenuti in ordine inverso::
>+
>+ <L1> -> <L2>
>+ <L2> -> <L1>
>+
>+perché porterebbe ad uno stallo - chiamato stallo da blocco inverso - in cui si
>+cerca di trattenere i due blocchi in un ciclo in cui entrambe i contesti
>+aspettano per sempre che l'altro termini. Il validatore è in grado di trovare
>+queste dipendenze cicliche di qualsiasi complessità, ovvero nel mezzo ci
>+potrebbero essere altre sequenze di blocchi. Il validatore troverà se questi
>+blocchi possono essere acquisiti circolarmente.
>+
>+In aggiunta, le seguenti sequenze di blocco nei contesti indicati non sono
>+permesse, indipendentemente da quale che sia la classe di blocco::
>+
>+ <hardirq-safe> -> <hardirq-unsafe>
>+ <softirq-safe> -> <softirq-unsafe>
>+
>+La prima regola deriva dal fatto che un blocco sicuro in interruzioni può essere
>+trattenuto in un contesto d'interruzione che, per definizione, ha la possibilità
>+di interrompere un blocco insicuro in interruzioni; questo porterebbe ad uno
>+stallo da blocco inverso. La seconda, analogamente, ci dice che un blocco sicuro
>+in interruzioni software potrebbe essere trattenuto in un contesto di
>+interruzione software, dunque potrebbe interrompere un blocco insicuro in
>+interruzioni software.
>+
>+Le suddette regole vengono applicate per qualsiasi sequenza di blocchi: quando
>+si acquisiscono nuovi blocchi, il validatore verifica se vi è una violazione
>+delle regole fra il nuovo blocco e quelli già trattenuti.
>+
>+Quando una classe di blocco cambia stato, applicheremo le seguenti regole:
>+
>+- se viene trovato un nuovo blocco sicuro in interruzioni, verificheremo se
>+ abbia mai trattenuto dei blocchi insicuri in interruzioni.
>+
>+- se viene trovato un nuovo blocco sicuro in interruzioni software,
>+ verificheremo se abbia trattenuto dei blocchi insicuri in interruzioni
>+ software.
>+
>+- se viene trovato un nuovo blocco insicuro in interruzioni, verificheremo se
>+ abbia trattenuto dei blocchi sicuri in interruzioni.
>+
>+- se viene trovato un nuovo blocco insicuro in interruzioni software,
>+ verificheremo se abbia trattenuto dei blocchi sicuri in interruzioni
>+ software.
>+
>+(Di nuovo, questi controlli vengono fatti perché un contesto d'interruzione
>+potrebbe interrompere l'esecuzione di qualsiasi blocco insicuro portando ad uno
>+stallo; questo anche se lo stallo non si verifica in pratica)
>+
>+Eccezione: dipendenze annidate sui dati portano a blocchi annidati
>+------------------------------------------------------------------
>+
>+Ci sono alcuni casi in cui il kernel Linux acquisisce più volte la stessa
>+istanza di una classe di blocco. Solitamente, questo succede quando esiste una
>+gerarchia fra oggetti dello stesso tipo. In questi casi viene ereditato
>+implicitamente l'ordine fra i due oggetti (definito dalle proprietà di questa
>+gerarchia), ed il kernel tratterrà i blocchi in questo ordine prefissato per
>+ognuno degli oggetti.
>+
>+Un esempio di questa gerarchia di oggetti che producono "blocchi annidati" sono
>+i *block-dev* che rappresentano l'intero disco e quelli che rappresentano una
>+sua partizione; la partizione è una parte del disco intero, e l'ordine dei
>+blocchi sarà corretto fintantoche uno acquisisce il blocco del disco intero e
>+poi quello della partizione. Il validatore non rileva automaticamente questo
>+ordine implicito, perché queste regole di sincronizzazione non sono statiche.
>+
>+Per istruire il validatore riguardo a questo uso corretto dei blocchi sono stati
>+introdotte nuove primitive per specificare i "livelli di annidamento". Per
>+esempio, per i blocchi a mutua esclusione dei *block-dev* si avrebbe una
>+chiamata simile a::
>+
>+ enum bdev_bd_mutex_lock_class
>+ {
>+ BD_MUTEX_NORMAL,
>+ BD_MUTEX_WHOLE,
>+ BD_MUTEX_PARTITION
>+ };
>+
>+ mutex_lock_nested(&bdev->bd_contains->bd_mutex, BD_MUTEX_PARTITION);
>+
>+In questo caso la sincronizzazione viene fatta su un *block-dev* sapendo che si
>+tratta di una partizione.
>+
>+Ai fini della validazione, il validatore lo considererà con una - sotto - classe
>+di blocco separata.
>+
>+Nota: Prestate estrema attenzione che la vostra gerarchia sia corretta quando si
>+vogliono usare le primitive _nested(); altrimenti potreste avere sia falsi
>+positivi che falsi negativi.
>+
>+Annotazioni
>+-----------
>+
>+Si possono utilizzare due costrutti per verificare ed annotare se certi blocchi
>+devono essere trattenuti: lockdep_assert_held*(&lock) e
>+lockdep_*pin_lock(&lock).
>+
>+Come suggerito dal nome, la famiglia di macro lockdep_assert_held* asseriscono
>+che un dato blocco in un dato momento deve essere trattenuto (altrimenti, verrà
>+generato un WARN()). Queste vengono usate abbondantemente nel kernel, per
>+esempio in kernel/sched/core.c::
>+
>+ void update_rq_clock(struct rq *rq)
>+ {
>+ s64 delta;
>+
>+ lockdep_assert_held(&rq->lock);
>+ [...]
>+ }
>+
>+dove aver trattenuto rq->lock è necessario per aggiornare in sicurezza il clock
>+rq.
>+
>+L'altra famiglia di macro è lockdep_*pin_lock(), che a dire il vero viene usata
>+solo per rq->lock ATM. Se per caso un blocco non viene trattenuto, queste
>+genereranno un WARN(). Questo si rivela particolarmente utile quando si deve
>+verificare la correttezza di codice con *callback*, dove livelli superiori
>+potrebbero assumere che un blocco rimanga trattenuto, ma livelli inferiori
>+potrebbero invece pensare che il blocco possa essere rilasciato e poi
>+riacquisito (involontariamente si apre una sezione critica). lockdep_pin_lock()
>+restituisce 'struct pin_cookie' che viene usato da lockdep_unpin_lock() per
>+verificare che nessuno abbia manomesso il blocco. Per esempio in
>+kernel/sched/sched.h abbiamo::
>+
>+ static inline void rq_pin_lock(struct rq *rq, struct rq_flags *rf)
>+ {
>+ rf->cookie = lockdep_pin_lock(&rq->lock);
>+ [...]
>+ }
>+
>+ static inline void rq_unpin_lock(struct rq *rq, struct rq_flags *rf)
>+ {
>+ [...]
>+ lockdep_unpin_lock(&rq->lock, rf->cookie);
>+ }
>+
>+I commenti riguardo alla sincronizzazione possano fornire informazioni utili,
>+tuttavia sono le verifiche in esecuzione effettuate da queste macro ad essere
>+vitali per scovare problemi di sincronizzazione, ed inoltre forniscono lo stesso
>+livello di informazioni quando si ispeziona il codice. Nel dubbio, preferite
>+queste annotazioni!
>+
>+Dimostrazione di correttezza al 100%
>+------------------------------------
>+
>+Il validatore verifica la proprietà di chiusura in senso matematico. Ovvero, per
>+ogni sequenza di sincronizzazione di un singolo processo che si verifichi almeno
>+una volta nel kernel, il validatore dimostrerà con una certezza del 100% che
>+nessuna combinazione e tempistica di queste sequenze possa causare uno stallo in
>+una qualsiasi classe di blocco. [1]_
>+
>+In pratica, per dimostrare l'esistenza di uno stallo non servono complessi
>+scenari di sincronizzazione multi-processore e multi-processo. Il validatore può
>+dimostrare la correttezza basandosi sulla sola sequenza di sincronizzazione
>+apparsa almeno una volta (in qualunque momento, in qualunque processo o
>+contesto). Uno scenario complesso che avrebbe bisogno di 3 processori e una
>+sfortunata presenza di processi, interruzioni, e pessimo tempismo, può essere
>+riprodotto su un sistema a singolo processore.
>+
>+Questo riduce drasticamente la complessità del controllo di qualità della
>+sincronizzazione nel kernel: quello che deve essere fatto è di innescare nel
>+kernel quante più possibili "semplici" sequenze di sincronizzazione, almeno una
>+volta, allo scopo di dimostrarne la correttezza. Questo al posto di innescare
>+una verifica per ogni possibile combinazione di sincronizzazione fra processori,
>+e differenti scenari con hardirq e softirq e annidamenti vari (nella pratica,
>+impossibile da fare)
>+
>+.. [1]
>+
>+ assumendo che il validatore sia corretto al 100%, e che nessun altra parte
>+ del sistema possa corromperne lo stato. Assumiamo anche che tutti i percorsi
>+ MNI/SMM [potrebbero interrompere anche percorsi dove le interruzioni sono
>+ disabilitate] sono corretti e non interferiscono con il validatore. Inoltre,
>+ assumiamo che un hash a 64-bit sia unico per ogni sequenza di
>+ sincronizzazione nel sistema. Infine, la ricorsione dei blocchi non deve
>+ essere maggiore di 20.
>+
>+Prestazione
>+-----------
>+
>+Le regole sopracitate hanno bisogno di una quantità **enorme** di verifiche
>+durante l'esecuzione. Il sistema sarebbe diventato praticamente inutilizzabile
>+per la sua lentezza se le avessimo fatte davvero per ogni blocco trattenuto e
>+per ogni abilitazione delle interruzioni. La complessità della verifica è
>+O(N^2), quindi avremmo dovuto fare decine di migliaia di verifiche per ogni
>+evento, il tutto per poche centinaia di classi.
>+
>+Il problema è stato risolto facendo una singola verifica per ogni 'scenario di
>+sincronizzazione' (una sequenza unica di blocchi trattenuti uno dopo l'altro).
>+Per farlo, viene mantenuta una pila dei blocchi trattenuti, e viene calcolato un
>+hash a 64-bit unico per ogni sequenza. Quando la sequenza viene verificata per
>+la prima volta, l'hash viene inserito in una tabella hash. La tabella potrà
>+essere verificata senza bisogno di blocchi. Se la sequenza dovesse ripetersi, la
>+tabella ci dirà che non è necessario verificarla nuovamente.
>+
>+Risoluzione dei problemi
>+------------------------
>+
>+Il massimo numero di classi di blocco che il validatore può tracciare è:
>+MAX_LOCKDEP_KEYS. Oltrepassare questo limite indurrà lokdep a generare il
>+seguente avviso::
>+
>+ (DEBUG_LOCKS_WARN_ON(id >= MAX_LOCKDEP_KEYS))
>+
>+Di base questo valore è 8191, e un classico sistema da ufficio ha meno di 1000
>+classi, dunque questo avviso è solitamente la conseguenza di un problema di
>+perdita delle classi di blocco o d'inizializzazione dei blocchi. Di seguito una
>+descrizione dei due problemi:
>+
>+1. caricare e rimuovere continuamente i moduli mentre il validatore è in
>+ esecuzione porterà ad una perdita di classi di blocco. Il problema è che ogni
>+ caricamento crea un nuovo insieme di classi di blocco per tutti i blocchi di
>+ quel modulo. Tuttavia, la rimozione del modulo non rimuove le vecchie classi
>+ (vedi dopo perché non le riusiamo). Dunque, il continuo caricamento e
>+ rimozione di un modulo non fa altro che aumentare il contatore di classi fino
>+ a raggiungere, eventualmente, il limite.
>+
>+2. Usare array con un gran numero di blocchi che non vengono esplicitamente
>+ inizializzati. Per esempio, una tabella hash con 8192 *bucket* dove ognuno ha
>+ il proprio spinlock_t consumerà 8192 classi di blocco a meno che non vengano
>+ esplicitamente inizializzati in esecuzione usando spin_lock_init() invece
>+ dell'inizializzazione durante la compilazione con __SPIN_LOCK_UNLOCKED().
>+ Sbagliare questa inizializzazione garantisce un esaurimento di classi di
>+ blocco. Viceversa, un ciclo che invoca spin_lock_init() su tutti i blocchi li
>+ mapperebbe tutti alla stessa classe di blocco.
>+
>+ La morale della favola è che dovete sempre inizializzare esplicitamente i
>+ vostri blocchi.
>+
>+Qualcuno potrebbe argomentare che il validatore debba permettere il riuso di
>+classi di blocco. Tuttavia, se siete tentati dall'argomento, prima revisionate
>+il codice e pensate alla modifiche necessarie, e tenendo a mente che le classi
>+di blocco da rimuovere probabilmente sono legate al grafo delle dipendenze. Più
>+facile a dirsi che a farsi.
>+
>+Ovviamente, se non esaurite le classi di blocco, la prossima cosa da fare è
>+quella di trovare le classi non funzionanti. Per prima cosa, il seguente comando
>+ritorna il numero di classi attualmente in uso assieme al valore massimo::
>+
>+ grep "lock-classes" /proc/lockdep_stats
>+
>+Questo comando produce il seguente messaggio::
>+
>+ lock-classes: 748 [max: 8191]
>+
>+Se il numero di assegnazioni (748 qui sopra) aumenta continuamente nel tempo,
>+allora c'è probabilmente un problema da qualche parte. Il seguente comando può
>+essere utilizzato per identificare le classi di blocchi problematiche::
>+
>+ grep "BD" /proc/lockdep
>+
>+Eseguite il comando e salvatene l'output, quindi confrontatelo con l'output di
>+un'esecuzione successiva per identificare eventuali problemi. Questo stesso
>+output può anche aiutarti a trovare situazioni in cui l'inizializzazione del
>+blocco è stata omessa.
>+
>+Lettura ricorsiva dei blocchi
>+-----------------------------
>+
>+Il resto di questo documento vuole dimostrare che certi cicli equivalgono ad una
>+possibilità di stallo.
>+
>+Ci sono tre tipi di bloccatori: gli scrittori (bloccatori esclusivi, come
>+spin_lock() o write_lock()), lettori non ricorsivi (bloccatori condivisi, come
>+down_read()), e lettori ricorsivi (bloccatori condivisi ricorsivi, come
>+rcu_read_lock()). D'ora in poi, per questi tipi di bloccatori, useremo la
>+seguente notazione:
>+
>+ W o E: per gli scrittori (bloccatori esclusivi) (W dall'inglese per
>+ *Writer*, ed E per *Exclusive*).
>+
>+ r: per i lettori non ricorsivi (r dall'inglese per *reader*).
>+
>+ R: per i lettori ricorsivi (R dall'inglese per *Reader*).
>+
>+ S: per qualsiasi lettore (non ricorsivi + ricorsivi), dato che entrambe
>+ sono bloccatori condivisi (S dall'inglese per *Shared*).
>+
>+ N: per gli scrittori ed i lettori non ricorsivi, dato che entrambe sono
>+ non ricorsivi.
>+
>+Ovviamente, N equivale a "r o W" ed S a "r o R".
>+
>+Come suggerisce il nome, i lettori ricorsivi sono dei bloccatori a cui è
>+permesso di acquisire la stessa istanza di blocco anche all'interno della
>+sezione critica di un altro lettore. In altre parole, permette di annidare la
>+stessa istanza di blocco nelle sezioni critiche dei lettori.
>+
>+Dall'altro canto, lo stesso comportamento indurrebbe un lettore non ricorsivo ad
>+auto infliggersi uno stallo.
>+
>+La differenza fra questi due tipi di lettori esiste perché: quelli ricorsivi
>+vengono bloccati solo dal trattenimento di un blocco di scrittura, mentre quelli
>+non ricorsivi possono essere bloccati dall'attesa di un blocco di scrittura.
>+Consideriamo il seguente esempio::
>+
>+ TASK A: TASK B:
>+
>+ read_lock(X);
>+ write_lock(X);
>+ read_lock_2(X);
>+
>+L'attività A acquisisce il blocco di lettura X (non importa se di tipo ricorsivo
>+o meno) usando read_lock(). Quando l'attività B tenterà di acquisire il blocco
>+X, si fermerà e rimarrà in attesa che venga rilasciato. Ora se read_lock_2() è
>+un tipo lettore ricorsivo, l'attività A continuerà perché gli scrittori in
>+attesa non possono bloccare lettori ricorsivi, e non avremo alcuno stallo.
>+Tuttavia, se read_lock_2() è un lettore non ricorsivo, allora verrà bloccato
>+dall'attività B e si causerà uno stallo.
>+
>+Condizioni bloccanti per lettori/scrittori su uno stesso blocco
>+---------------------------------------------------------------
>+Essenzialmente ci sono quattro condizioni bloccanti:
>+
>+1. Uno scrittore blocca un altro scrittore.
>+2. Un lettore blocca uno scrittore.
>+3. Uno scrittore blocca sia i lettori ricorsivi che non ricorsivi.
>+4. Un lettore (ricorsivo o meno) non blocca altri lettori ricorsivi ma potrebbe
>+ bloccare quelli non ricorsivi (perché potrebbero esistere degli scrittori in
>+ attesa).
>+
>+Di seguito le tabella delle condizioni bloccanti, Y (*Yes*) significa che il
>+tipo in riga blocca quello in colonna, mentre N l'opposto.
>+
>+ +---+---+---+---+
>+ | | W | r | R |
>+ +---+---+---+---+
>+ | W | Y | Y | Y |
>+ +---+---+---+---+
>+ | r | Y | Y | N |
>+ +---+---+---+---+
>+ | R | Y | Y | N |
>+ +---+---+---+---+
>+
>+ (W: scrittori, r: lettori non ricorsivi, R: lettori ricorsivi)
>+
>+Al contrario dei blocchi per lettori non ricorsivi, quelli ricorsivi vengono
>+trattenuti da chi trattiene il blocco di scrittura piuttosto che da chi ne
>+attende il rilascio. Per esempio::
>+
>+ TASK A: TASK B:
>+
>+ read_lock(X);
>+
>+ write_lock(X);
>+
>+ read_lock(X);
>+
>+non produce uno stallo per i lettori ricorsivi, in quanto il processo B rimane
>+in attesta del blocco X, mentre il secondo read_lock() non ha bisogno di
>+aspettare perché si tratta di un lettore ricorsivo. Tuttavia, se read_lock()
>+fosse un lettore non ricorsivo, questo codice produrrebbe uno stallo.
>+
>+Da notare che in funzione dell'operazione di blocco usate per l'acquisizione (in
>+particolare il valore del parametro 'read' in lock_acquire()), un blocco può
>+essere di scrittura (blocco esclusivo), di lettura non ricorsivo (blocco
>+condiviso e non ricorsivo), o di lettura ricorsivo (blocco condiviso e
>+ricorsivo). In altre parole, per un'istanza di blocco esistono tre tipi di
>+acquisizione che dipendono dalla funzione di acquisizione usata: esclusiva, di
>+lettura non ricorsiva, e di lettura ricorsiva.
>+
>+In breve, chiamiamo "non ricorsivi" blocchi di scrittura e quelli di lettura non
>+ricorsiva, mentre "ricorsivi" i blocchi di lettura ricorsivi.
>+
>+I blocchi ricorsivi non si bloccano a vicenda, mentre quelli non ricorsivi sì
>+(anche in lettura). Un blocco di lettura non ricorsivi può bloccare uno
>+ricorsivo, e viceversa.
>+
>+Il seguente esempio mostra uno stallo con blocchi ricorsivi::
>+
>+ TASK A: TASK B:
>+
>+ read_lock(X);
>+ read_lock(Y);
>+ write_lock(Y);
>+ write_lock(X);
>+
>+Il processo A attende che il processo B esegua read_unlock() so Y, mentre il
>+processo B attende che A esegua read_unlock() su X.
>+
>+Tipi di dipendenze e percorsi forti
>+-----------------------------------
>+Le dipendenze fra blocchi tracciano l'ordine con cui una coppia di blocchi viene
>+acquisita, e perché vi sono 3 tipi di bloccatori, allora avremo 9 tipi di
>+dipendenze. Tuttavia, vi mostreremo che 4 sono sufficienti per individuare gli
>+stalli.
>+
>+Per ogni dipendenza fra blocchi avremo::
>+
>+ L1 -> L2
>+
>+Questo significa che lockdep ha visto acquisire L1 prima di L2 nello stesso
>+contesto di esecuzione. Per quanto riguarda l'individuazione degli stalli, ci
>+interessa sapere se possiamo rimanere bloccati da L2 mentre L1 viene trattenuto.
>+In altre parole, vogliamo sapere se esiste un bloccatore L3 che viene bloccato
>+da L1 e un L2 che viene bloccato da L3. Dunque, siamo interessati a (1) quello
>+che L1 blocca e (2) quello che blocca L2. Di conseguenza, possiamo combinare
>+lettori ricorsivi e non per L1 (perché bloccano gli stessi tipi) e possiamo
>+combinare scrittori e lettori non ricorsivi per L2 (perché vengono bloccati
>+dagli stessi tipi).
>+
>+Con questa semplificazione, possiamo dedurre che ci sono 4 tipi di rami nel
>+grafo delle dipendenze di lockdep:
>+
>+1) -(ER)->:
>+ dipendenza da scrittore esclusivo a lettore ricorsivo. "X -(ER)-> Y"
>+ significa X -> Y, dove X è uno scrittore e Y un lettore ricorsivo.
>+
>+2) -(EN)->:
>+ dipendenza da scrittore esclusivo a bloccatore non ricorsivo.
>+ "X -(EN)->" significa X-> Y, dove X è uno scrittore e Y può essere
>+ o uno scrittore o un lettore non ricorsivo.
>+
>+3) -(SR)->:
>+ dipendenza da lettore condiviso a lettore ricorsivo. "X -(SR)->"
>+ significa X -> Y, dove X è un lettore (ricorsivo o meno) e Y è un
>+ lettore ricorsivo.
>+
>+4) -(SN)->:
>+ dipendenza da lettore condiviso a bloccatore non ricorsivo.
>+ "X -(SN)-> Y" significa X -> Y , dove X è un lettore (ricorsivo
>+ o meno) e Y può essere o uno scrittore o un lettore non ricorsivo.
>+
>+Da notare che presi due blocchi, questi potrebbero avere più dipendenza fra di
>+loro. Per esempio::
>+
>+ TASK A:
>+
>+ read_lock(X);
>+ write_lock(Y);
>+ ...
>+
>+ TASK B:
>+
>+ write_lock(X);
>+ write_lock(Y);
>+
>+Nel grafo delle dipendenze avremo sia X -(SN)-> Y che X -(EN)-> Y.
>+
>+Usiamo -(xN)-> per rappresentare i rami sia per -(EN)-> che -(SN)->, allo stesso
>+modo -(Ex)->, -(xR)-> e -(Sx)->
>+
>+Un "percorso" in un grafo è una serie di nodi e degli archi che li congiungono.
>+Definiamo un percorso "forte", come il percorso che non ha archi (dipendenze) di
>+tipo -(xR)-> e -(Sx)->. In altre parole, un percorso "forte" è un percorso da un
>+blocco ad un altro attraverso le varie dipendenze, e se sul percorso abbiamo X
>+-> Y -> Z (dove X, Y, e Z sono blocchi), e da X a Y si ha una dipendenza -(SR)->
>+o -(ER)->, allora fra Y e Z non deve esserci una dipendenza -(SN)-> o -(SR)->.
>+
>+Nella prossima sezione vedremo perché definiamo questo percorso "forte".
>+
>+Identificazione di stalli da lettura ricorsiva
>+----------------------------------------------
>+Ora vogliamo dimostrare altre due cose:
>+
>+Lemma 1:
>+
>+Se esiste un percorso chiuso forte (ciclo forte), allora esiste anche una
>+combinazione di sequenze di blocchi che causa uno stallo. In altre parole,
>+l'esistenza di un ciclo forte è sufficiente alla scoperta di uno stallo.
>+
>+Lemma 2:
>+
>+Se non esiste un percorso chiuso forte (ciclo forte), allora non esiste una
>+combinazione di sequenze di blocchi che causino uno stallo. In altre parole, i
>+cicli forti sono necessari alla rilevazione degli stallo.
>+
>+Con questi due lemmi possiamo facilmente affermare che un percorso chiuso forte
>+è sia sufficiente che necessario per avere gli stalli, dunque averli equivale
>+alla possibilità di imbattersi concretamente in uno stallo. Un percorso chiuso
>+forte significa che può causare stalli, per questo lo definiamo "forte", ma ci
>+sono anche cicli di dipendenze che non causeranno stalli.
>+
>+Dimostrazione di sufficienza (lemma 1):
>+
>+Immaginiamo d'avere un ciclo forte::
>+
>+ L1 -> L2 ... -> Ln -> L1
>+
>+Questo significa che abbiamo le seguenti dipendenze::
>+
>+ L1 -> L2
>+ L2 -> L3
>+ ...
>+ Ln-1 -> Ln
>+ Ln -> L1
>+
>+Ora possiamo costruire una combinazione di sequenze di blocchi che causano lo
>+stallo.
>+
>+Per prima cosa facciamo sì che un processo/processore prenda L1 in L1 -> L2, poi
>+un altro prende L2 in L2 -> L3, e così via. Alla fine, tutti i Lx in Lx -> Lx+1
>+saranno trattenuti da processi/processori diversi.
>+
>+Poi visto che abbiamo L1 -> L2, chi trattiene L1 vorrà acquisire L2 in L1 -> L2,
>+ma prima dovrà attendere che venga rilasciato da chi lo trattiene. Questo perché
>+L2 è già trattenuto da un altro processo/processore, ed in più L1 -> L2 e L2 ->
>+L3 non sono -(xR)-> né -(Sx)-> (la definizione di forte). Questo significa che L2
>+in L1 -> L2 non è un bloccatore non ricorsivo (bloccabile da chiunque), e L2 in
>+L2 -> L3 non è uno scrittore (che blocca chiunque).
>+
>+In aggiunta, possiamo trarre una simile conclusione per chi sta trattenendo L2:
>+deve aspettare che L3 venga rilasciato, e così via. Ora possiamo dimostrare che
>+chi trattiene Lx deve aspettare che Lx+1 venga rilasciato. Notiamo che Ln+1 è
>+L1, dunque si è creato un ciclo dal quale non possiamo uscire, quindi si ha uno
>+stallo.
>+
>+Dimostrazione della necessità (lemma 2):
>+
>+Questo lemma equivale a dire che: se siamo in uno scenario di stallo, allora
>+deve esiste un ciclo forte nel grafo delle dipendenze.
>+
>+Secondo Wikipedia[1], se c'è uno stallo, allora deve esserci un ciclo di attese,
>+ovvero ci sono N processi/processori dove P1 aspetta un blocco trattenuto da P2,
>+e P2 ne aspetta uno trattenuto da P3, ... e Pn attende che il blocco P1 venga
>+rilasciato. Chiamiamo Lx il blocco che attende Px, quindi P1 aspetta L1 e
>+trattiene Ln. Quindi avremo Ln -> L1 nel grafo delle dipendenze. Similarmente,
>+nel grafo delle dipendenze avremo L1 -> L2, L2 -> L3, ..., Ln-1 -> Ln, il che
>+significa che abbiamo un ciclo::
>+
>+ Ln -> L1 -> L2 -> ... -> Ln
>+
>+, ed ora dimostriamo d'avere un ciclo forte.
>+
>+Per un blocco Lx, il processo Px contribuisce alla dipendenza Lx-1 -> Lx e Px+1
>+contribuisce a quella Lx -> Lx+1. Visto che Px aspetta che Px+1 rilasci Lx, sarà
>+impossibile che Lx in Px+1 sia un lettore e che Lx in Px sia un lettore
>+ricorsivo. Questo perché i lettori (ricorsivi o meno) non bloccano lettori
>+ricorsivi. Dunque, Lx-1 -> Lx e Lx -> Lx+1 non possono essere una coppia di
>+-(xR)-> -(Sx)->. Questo è vero per ogni ciclo, dunque, questo è un ciclo forte.
>+
>+Riferimenti
>+-----------
>+
>+[1]: https://it.wikipedia.org/wiki/Stallo_(informatica)
>+
>+[2]: Shibu, K. (2009). Intro To Embedded Systems (1st ed.). Tata McGraw-Hill
>diff --git a/Documentation/translations/it_IT/locking/lockstat.rst b/Documentation/translations/it_IT/locking/lockstat.rst
>new file mode 100644
>index 000000000000..77972d971d7c
>--- /dev/null
>+++ b/Documentation/translations/it_IT/locking/lockstat.rst
>@@ -0,0 +1,230 @@
>+.. SPDX-License-Identifier: GPL-2.0
>+
>+.. include:: ../disclaimer-ita.rst
>+
>+=======================
>+Statistiche sui blocchi
>+=======================
>+
>+Cosa
>+====
>+
>+Come suggerisce il nome, fornisce statistiche sui blocchi.
>+
>+
>+Perché
>+======
>+
>+Perché, tanto per fare un esempio, le contese sui blocchi possono influenzare
>+significativamente le prestazioni.
>+
>+Come
>+====
>+
>+*Lockdep* ha punti di collegamento nelle funzioni di blocco e inoltre
>+mappa le istanze di blocco con le relative classi. Partiamo da questo punto
>+(vedere Documentation/translations/it_IT/locking/lockdep-design.rst).
>+Il grafico sottostante mostra la relazione che intercorre fra le
>+funzioni di blocco e i vari punti di collegamenti che ci sono al loro
>+interno::
>+
>+ __acquire
>+ |
>+ lock _____
>+ | \
>+ | __contended
>+ | |
>+ | <wait>
>+ | _______/
>+ |/
>+ |
>+ __acquired
>+ |
>+ .
>+ <hold>
>+ .
>+ |
>+ __release
>+ |
>+ unlock
>+
>+ lock, unlock - le classiche funzioni di blocco
>+ __* - i punti di collegamento
>+ <> - stati
>+
>+Grazie a questi punti di collegamento possiamo fornire le seguenti statistiche:
>+
>+con-bounces
>+ - numero di contese su un blocco che riguarda dati di un processore
>+
>+contentions
>+ - numero di acquisizioni di blocchi che hanno dovuto attendere
>+
>+wait time
>+ min
>+ - tempo minimo (diverso da zero) che sia mai stato speso in attesa di
>+ un blocco
>+
>+ max
>+ - tempo massimo che sia mai stato speso in attesa di un blocco
>+
>+ total
>+ - tempo totale speso in attesa di un blocco
>+
>+ avg
>+ - tempo medio speso in attesa di un blocco
>+
>+acq-bounces
>+ - numero di acquisizioni di blocco che riguardavano i dati su un processore
>+
>+acquisitions
>+ - numero di volte che un blocco è stato ottenuto
>+
>+hold time
>+ min
>+ - tempo minimo (diverso da zero) che sia mai stato speso trattenendo un blocco
>+
>+ max
>+ - tempo massimo che sia mai stato speso trattenendo un blocco
>+
>+ total
>+ - tempo totale di trattenimento di un blocco
>+
>+ avg
>+ - tempo medio di trattenimento di un blocco
>+
>+Questi numeri vengono raccolti per classe di blocco, e per ogni stato di
>+lettura/scrittura (quando applicabile).
>+
>+Inoltre, questa raccolta di statistiche tiene traccia di 4 punti di contesa
>+per classe di blocco. Un punto di contesa è una chiamata che ha dovuto
>+aspettare l'acquisizione di un blocco.
>+
>+Configurazione
>+--------------
>+
>+Le statistiche sui blocchi si abilitano usando l'opzione di configurazione
>+CONFIG_LOCK_STAT.
>+
>+Uso
>+---
>+
>+Abilitare la raccolta di statistiche::
>+
>+ # echo 1 >/proc/sys/kernel/lock_stat
>+
>+Disabilitare la raccolta di statistiche::
>+
>+ # echo 0 >/proc/sys/kernel/lock_stat
>+
>+Per vedere le statistiche correnti sui blocchi::
>+
>+ ( i numeri di riga non fanno parte dell'output del comando, ma sono stati
>+ aggiunti ai fini di questa spiegazione )
>+
>+ # less /proc/lock_stat
>+
>+ 01 lock_stat version 0.4
>+ 02-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>+ 03 class name con-bounces contentions waittime-min waittime-max waittime-total waittime-avg acq-bounces acquisitions holdtime-min holdtime-max holdtime-total holdtime-avg
>+ 04-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>+ 05
>+ 06 &mm->mmap_sem-W: 46 84 0.26 939.10 16371.53 194.90 47291 2922365 0.16 2220301.69 17464026916.32 5975.99
>+ 07 &mm->mmap_sem-R: 37 100 1.31 299502.61 325629.52 3256.30 212344 34316685 0.10 7744.91 95016910.20 2.77
>+ 08 ---------------
>+ 09 &mm->mmap_sem 1 [<ffffffff811502a7>] khugepaged_scan_mm_slot+0x57/0x280
>+ 10 &mm->mmap_sem 96 [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
>+ 11 &mm->mmap_sem 34 [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
>+ 12 &mm->mmap_sem 17 [<ffffffff81127e71>] vm_munmap+0x41/0x80
>+ 13 ---------------
>+ 14 &mm->mmap_sem 1 [<ffffffff81046fda>] dup_mmap+0x2a/0x3f0
>+ 15 &mm->mmap_sem 60 [<ffffffff81129e29>] SyS_mprotect+0xe9/0x250
>+ 16 &mm->mmap_sem 41 [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
>+ 17 &mm->mmap_sem 68 [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
>+ 18
>+ 19.............................................................................................................................................................................................................................
>+ 20
>+ 21 unix_table_lock: 110 112 0.21 49.24 163.91 1.46 21094 66312 0.12 624.42 31589.81 0.48
>+ 22 ---------------
>+ 23 unix_table_lock 45 [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
>+ 24 unix_table_lock 47 [<ffffffff8150b111>] unix_release_sock+0x31/0x250
>+ 25 unix_table_lock 15 [<ffffffff8150ca37>] unix_find_other+0x117/0x230
>+ 26 unix_table_lock 5 [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
>+ 27 ---------------
>+ 28 unix_table_lock 39 [<ffffffff8150b111>] unix_release_sock+0x31/0x250
>+ 29 unix_table_lock 49 [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
>+ 30 unix_table_lock 20 [<ffffffff8150ca37>] unix_find_other+0x117/0x230
>+ 31 unix_table_lock 4 [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
>+
>+Questo estratto mostra le statistiche delle prime due classi di
>+blocco. La riga 01 mostra la versione dell'output - la versione
>+cambierà ogni volta che cambia il formato. Le righe dalla 02 alla 04
>+rappresentano l'intestazione con la descrizione delle colonne. Le
>+statistiche sono mostrate nelle righe dalla 05 alla 18 e dalla 20
>+alla 31. Queste statistiche sono divise in due parti: le statistiche,
>+seguite dai punti di contesa (righe 08 e 13) separati da un divisore.
>+
>+Le righe dalla 09 alla 12 mostrano i primi quattro punti di contesa
>+registrati (il codice che tenta di acquisire un blocco) e le righe
>+dalla 14 alla 17 mostrano i primi quattro punti contesi registrati
>+(ovvero codice che ha acquisito un blocco). È possibile che nelle
>+statistiche manchi il valore *max con-bounces*.
>+
>+Il primo blocco (righe dalla 05 alla 18) è di tipo lettura/scrittura e quindi
>+mostra due righe prima del divisore. I punti di contesa non corrispondono alla
>+descrizione delle colonne nell'intestazione; essi hanno due colonne: *punti di
>+contesa* e *[<IP>] simboli*. Il secondo gruppo di punti di contesa sono i punti
>+con cui si contende il blocco.
>+
>+La parte interna del tempo è espressa in us (microsecondi).
>+
>+Quando si ha a che fare con blocchi annidati si potrebbero vedere le
>+sottoclassi di blocco::
>+
>+ 32...........................................................................................................................................................................................................................
>+ 33
>+ 34 &rq->lock: 13128 13128 0.43 190.53 103881.26 7.91 97454 3453404 0.00 401.11 13224683.11 3.82
>+ 35 ---------
>+ 36 &rq->lock 645 [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
>+ 37 &rq->lock 297 [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
>+ 38 &rq->lock 360 [<ffffffff8103c4c5>] select_task_rq_fair+0x1f0/0x74a
>+ 39 &rq->lock 428 [<ffffffff81045f98>] scheduler_tick+0x46/0x1fb
>+ 40 ---------
>+ 41 &rq->lock 77 [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
>+ 42 &rq->lock 174 [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
>+ 43 &rq->lock 4715 [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
>+ 44 &rq->lock 893 [<ffffffff81340524>] schedule+0x157/0x7b8
>+ 45
>+ 46...........................................................................................................................................................................................................................
>+ 47
>+ 48 &rq->lock/1: 1526 11488 0.33 388.73 136294.31 11.86 21461 38404 0.00 37.93 109388.53 2.84
>+ 49 -----------
>+ 50 &rq->lock/1 11526 [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
>+ 51 -----------
>+ 52 &rq->lock/1 5645 [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
>+ 53 &rq->lock/1 1224 [<ffffffff81340524>] schedule+0x157/0x7b8
>+ 54 &rq->lock/1 4336 [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
>+ 55 &rq->lock/1 181 [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
>+
>+La riga 48 mostra le statistiche per la seconda sottoclasse (/1) della
>+classe *&irq->lock* (le sottoclassi partono da 0); in questo caso,
>+come suggerito dalla riga 50, ``double_rq_lock`` tenta di acquisire un blocco
>+annidato di due spinlock.
>+
>+Per vedere i blocco più contesi::
>+
>+ # grep : /proc/lock_stat | head
>+ clockevents_lock: 2926159 2947636 0.15 46882.81 1784540466.34 605.41 3381345 3879161 0.00 2260.97 53178395.68 13.71
>+ tick_broadcast_lock: 346460 346717 0.18 2257.43 39364622.71 113.54 3642919 4242696 0.00 2263.79 49173646.60 11.59
>+ &mapping->i_mmap_mutex: 203896 203899 3.36 645530.05 31767507988.39 155800.21 3361776 8893984 0.17 2254.15 14110121.02 1.59
>+ &rq->lock: 135014 136909 0.18 606.09 842160.68 6.15 1540728 10436146 0.00 728.72 17606683.41 1.69
>+ &(&zone->lru_lock)->rlock: 93000 94934 0.16 59.18 188253.78 1.98 1199912 3809894 0.15 391.40 3559518.81 0.93
>+ tasklist_lock-W: 40667 41130 0.23 1189.42 428980.51 10.43 270278 510106 0.16 653.51 3939674.91 7.72
>+ tasklist_lock-R: 21298 21305 0.20 1310.05 215511.12 10.12 186204 241258 0.14 1162.33 1179779.23 4.89
>+ rcu_node_1: 47656 49022 0.16 635.41 193616.41 3.95 844888 1865423 0.00 764.26 1656226.96 0.89
>+ &(&dentry->d_lockref.lock)->rlock: 39791 40179 0.15 1302.08 88851.96 2.21 2790851 12527025 0.10 1910.75 3379714.27 0.27
>+ rcu_node_0: 29203 30064 0.16 786.55 1555573.00 51.74 88963 244254 0.00 398.87 428872.51 1.76
>+
>+Per cancellare le statistiche::
>+
>+ # echo 0 > /proc/lock_stat
>diff --git a/Documentation/translations/it_IT/locking/locktorture.rst b/Documentation/translations/it_IT/locking/locktorture.rst
>new file mode 100644
>index 000000000000..87a0dbeaca77
>--- /dev/null
>+++ b/Documentation/translations/it_IT/locking/locktorture.rst
>@@ -0,0 +1,181 @@
>+.. SPDX-License-Identifier: GPL-2.0
>+
>+.. include:: ../disclaimer-ita.rst
>+
>+============================================
>+Funzionamento del test *Kernel Lock Torture*
>+============================================
>+
>+CONFIG_LOCK_TORTURE_TEST
>+========================
>+
>+L'opzione di configurazione CONFIG_LOCK_TORTURE_TEST fornisce un
>+modulo kernel che esegue delle verifiche che *torturano* le primitive di
>+sincronizzazione del kernel. Se dovesse servire, il modulo kernel,
>+'locktorture', può essere generato successivamente su un kernel che
>+volete verificare. Periodicamente le verifiche stampano messaggi tramite
>+``printk()`` e che quindi possono essere letti tramite ``dmesg`` (magari
>+filtrate l'output con ``grep "torture"``). La verifica inizia quando
>+il modulo viene caricato e termina quando viene rimosso. Questo
>+programma si basa sulle modalità di verifica di RCU tramite rcutorture.
>+
>+Questa verifica consiste nella creazione di un certo numero di thread
>+del kernel che acquisiscono un blocco e lo trattengono per una certa
>+quantità di tempo così da simulare diversi comportamenti nelle sezioni
>+critiche. La quantità di contese su un blocco può essere simulata
>+allargando la sezione critica e/o creando più thread.
>+
>+
>+Parametri del modulo
>+====================
>+
>+Questo modulo ha i seguenti parametri:
>+
>+
>+Specifici di locktorture
>+------------------------
>+
>+nwriters_stress
>+ Numero di thread del kernel che stresseranno l'acquisizione
>+ esclusiva dei blocchi (scrittori). Il valore di base è il
>+ doppio del numero di processori attivi presenti.
>+
>+nreaders_stress
>+ Numero di thread del kernel che stresseranno l'acquisizione
>+ condivisa dei blocchi (lettori). Il valore di base è lo stesso
>+ di nwriters_stress. Se l'utente non ha specificato
>+ nwriters_stress, allora entrambe i valori corrisponderanno
>+ al numero di processori attivi presenti.
>+
>+torture_type
>+ Tipo di blocco da verificare. Di base, solo gli spinlock
>+ verranno verificati. Questo modulo può verificare anche
>+ i seguenti tipi di blocchi:
>+
>+ - "lock_busted":
>+ Simula un'incorretta implementazione del
>+ blocco.
>+
>+ - "spin_lock":
>+ coppie di spin_lock() e spin_unlock().
>+
>+ - "spin_lock_irq":
>+ coppie di spin_lock_irq() e spin_unlock_irq().
>+
>+ - "rw_lock":
>+ coppie di rwlock read/write lock() e unlock().
>+
>+ - "rw_lock_irq":
>+ copie di rwlock read/write lock_irq() e
>+ unlock_irq().
>+
>+ - "mutex_lock":
>+ coppie di mutex_lock() e mutex_unlock().
>+
>+ - "rtmutex_lock":
>+ coppie di rtmutex_lock() e rtmutex_unlock().
>+ Il kernel deve avere CONFIG_RT_MUTEXES=y.
>+
>+ - "rwsem_lock":
>+ coppie di semafori read/write down() e up().
>+
>+
>+Generici dell'ambiente di sviluppo 'torture' (RCU + locking)
>+------------------------------------------------------------
>+
>+shutdown_secs
>+ Numero di secondi prima che la verifica termini e il sistema
>+ venga spento. Il valore di base è zero, il che disabilita
>+ la possibilità di terminare e spegnere. Questa funzionalità
>+ può essere utile per verifiche automatizzate.
>+
>+onoff_interval
>+ Numero di secondi fra ogni tentativo di esecuzione di
>+ un'operazione casuale di CPU-hotplug. Di base è zero, il
>+ che disabilita la funzionalità di CPU-hotplug. Nei kernel
>+ con CONFIG_HOTPLUG_CPU=n, locktorture si rifiuterà, senza
>+ dirlo, di effettuare una qualsiasi operazione di
>+ CPU-hotplug indipendentemente dal valore specificato in
>+ onoff_interval.
>+
>+onoff_holdoff
>+ Numero di secondi da aspettare prima di iniziare le
>+ operazioni di CPU-hotplug. Normalmente questo verrebbe
>+ usato solamente quando locktorture è compilato come parte
>+ integrante del kernel ed eseguito automaticamente all'avvio,
>+ in questo caso è utile perché permette di non confondere
>+ l'avvio con i processori che vanno e vengono. Questo
>+ parametro è utile sono se CONFIG_HOTPLUG_CPU è abilitato.
>+
>+stat_interval
>+ Numero di secondi fra una stampa (printk()) delle
>+ statistiche e l'altra. Di base, locktorture riporta le
>+ statistiche ogni 60 secondi. Impostando l'intervallo a 0
>+ ha l'effetto di stampare le statistiche -solo- quando il
>+ modulo viene rimosso.
>+
>+stutter
>+ Durata della verifica prima di effettuare una pausa di
>+ eguale durata. Di base "stutter=5", quindi si eseguono
>+ verifiche e pause di (circa) cinque secondi.
>+ L'impostazione di "stutter=0" fa si che la verifica
>+ venga eseguita continuamente senza fermarsi.
>+
>+shuffle_interval
>+ Il numero di secondi per cui un thread debba mantenere
>+ l'affinità con un sottoinsieme di processori, di base è
>+ 3 secondi. Viene usato assieme a test_no_idle_hz.
>+
>+verbose
>+ Abilita le stampe di debug, via printk(). Di base è
>+ abilitato. Queste informazioni aggiuntive sono per la
>+ maggior parte relative ad errori di alto livello e resoconti
>+ da parte dell'struttura 'torture'.
>+
>+
>+Statistiche
>+===========
>+
>+Le statistiche vengono stampate secondo il seguente formato::
>+
>+ spin_lock-torture: Writes: Total: 93746064 Max/Min: 0/0 Fail: 0
>+ (A) (B) (C) (D) (E)
>+
>+ (A): tipo di lock sotto verifica -- parametro torture_type.
>+
>+ (B): Numero di acquisizione del blocco in scrittura. Se si ha a che fare
>+ con una primitiva di lettura/scrittura apparirà di seguito anche una
>+ seconda voce "Reads"
>+
>+ (C): Numero di volte che il blocco è stato acquisito
>+
>+ (D): Numero minimo e massimo di volte che un thread ha fallito
>+ nell'acquisire il blocco
>+
>+ (E): valori true/false nel caso di errori durante l'acquisizione del blocco.
>+ Questo dovrebbe dare un riscontro positivo -solo- se c'è un baco
>+ nell'implementazione delle primitive di sincronizzazione. Altrimenti un
>+ blocco non dovrebbe mai fallire (per esempio, spin_lock()).
>+ Ovviamente lo stesso si applica per (C). Un semplice esempio è il tipo
>+ "lock_busted".
>+
>+Uso
>+===
>+
>+Il seguente script può essere utilizzato per verificare i blocchi::
>+
>+ #!/bin/sh
>+
>+ modprobe locktorture
>+ sleep 3600
>+ rmmod locktorture
>+ dmesg | grep torture:
>+
>+L'output può essere manualmente ispezionato cercando il marcatore d'errore
>+"!!!". Ovviamente potreste voler creare degli script più elaborati che
>+verificano automaticamente la presenza di errori. Il comando "rmmod" forza la
>+stampa (usando printk()) di "SUCCESS", "FAILURE", oppure "RCU_HOTPLUG". I primi
>+due si piegano da soli, mentre l'ultimo indica che non stati trovati problemi di
>+sincronizzazione, tuttavia ne sono stati trovati in CPU-hotplug.
>+
>+Consultate anche: Documentation/translations/it_IT/RCU/torture.rst
>diff --git a/Documentation/translations/it_IT/locking/locktypes.rst b/Documentation/translations/it_IT/locking/locktypes.rst
>new file mode 100644
>index 000000000000..1c7056283b9d
>--- /dev/null
>+++ b/Documentation/translations/it_IT/locking/locktypes.rst
>@@ -0,0 +1,547 @@
>+.. SPDX-License-Identifier: GPL-2.0
>+
>+.. include:: ../disclaimer-ita.rst
>+
>+.. _it_kernel_hacking_locktypes:
>+
>+========================================
>+Tipologie di blocco e le loro istruzioni
>+========================================
>+
>+Introduzione
>+============
>+
>+Il kernel fornisce un certo numero di primitive di blocco che possiamo dividere
>+in tre categorie:
>+
>+ - blocchi ad attesa con sospensione
>+ - blocchi locali per CPU
>+ - blocchi ad attesa attiva
>+
>+Questo documento descrive questi tre tipi e fornisce istruzioni su come
>+annidarli, ed usarli su kernel PREEMPT_RT.
>+
>+Categorie di blocchi
>+====================
>+
>+Blocchi ad attesa con sospensione
>+---------------------------------
>+
>+I blocchi ad attesa con sospensione possono essere acquisiti solo in un contesti
>+dov'è possibile la prelazione.
>+
>+Diverse implementazioni permettono di usare try_lock() anche in altri contesti,
>+nonostante ciò è bene considerare anche la sicurezza dei corrispondenti
>+unlock(). Inoltre, vanno prese in considerazione anche le varianti di *debug*
>+di queste primitive. Insomma, non usate i blocchi ad attesa con sospensioni in
>+altri contesti a meno che proprio non vi siano alternative.
>+
>+In questa categoria troviamo:
>+
>+ - mutex
>+ - rt_mutex
>+ - semaphore
>+ - rw_semaphore
>+ - ww_mutex
>+ - percpu_rw_semaphore
>+
>+Nei kernel con PREEMPT_RT, i seguenti blocchi sono convertiti in blocchi ad
>+attesa con sospensione:
>+
>+ - local_lock
>+ - spinlock_t
>+ - rwlock_t
>+
>+Blocchi locali per CPU
>+----------------------
>+
>+ - local_lock
>+
>+Su kernel non-PREEMPT_RT, le funzioni local_lock gestiscono le primitive di
>+disabilitazione di prelazione ed interruzioni. Al contrario di altri meccanismi,
>+la disabilitazione della prelazione o delle interruzioni sono puri meccanismi
>+per il controllo della concorrenza su una CPU e quindi non sono adatti per la
>+gestione della concorrenza inter-CPU.
>+
>+Blocchi ad attesa attiva
>+------------------------
>+
>+ - raw_spinlcok_t
>+ - bit spinlocks
>+
>+ Nei kernel non-PREEMPT_RT, i seguenti blocchi sono ad attesa attiva:
>+
>+ - spinlock_t
>+ - rwlock_t
>+
>+Implicitamente, i blocchi ad attesa attiva disabilitano la prelazione e le
>+funzioni lock/unlock hanno anche dei suffissi per gestire il livello di
>+protezione:
>+
>+ =================== =========================================================================
>+ _bh() disabilita / abilita *bottom halves* (interruzioni software)
>+ _irq() disabilita / abilita le interruzioni
>+ _irqsave/restore() salva e disabilita le interruzioni / ripristina ed attiva le interruzioni
>+ =================== =========================================================================
>+
>+Semantica del proprietario
>+==========================
>+
>+Eccetto i semafori, i sopracitati tipi di blocchi hanno tutti una semantica
>+molto stringente riguardo al proprietario di un blocco:
>+
>+ Il contesto (attività) che ha acquisito il blocco deve rilasciarlo
>+
>+I semafori rw_semaphores hanno un'interfaccia speciale che permette anche ai non
>+proprietari del blocco di rilasciarlo per i lettori.
>+
>+rtmutex
>+=======
>+
>+I blocchi a mutua esclusione RT (*rtmutex*) sono un sistema a mutua esclusione
>+con supporto all'ereditarietà della priorità (PI).
>+
>+Questo meccanismo ha delle limitazioni sui kernel non-PREEMPT_RT dovuti alla
>+prelazione e alle sezioni con interruzioni disabilitate.
>+
>+Chiaramente, questo meccanismo non può avvalersi della prelazione su una sezione
>+dove la prelazione o le interruzioni sono disabilitate; anche sui kernel
>+PREEMPT_RT. Tuttavia, i kernel PREEMPT_RT eseguono la maggior parte delle
>+sezioni in contesti dov'è possibile la prelazione, specialmente in contesti
>+d'interruzione (anche software). Questa conversione permette a spinlock_t e
>+rwlock_t di essere implementati usando rtmutex.
>+
>+semaphore
>+=========
>+
>+La primitiva semaphore implementa un semaforo con contatore.
>+
>+I semafori vengono spesso utilizzati per la serializzazione e l'attesa, ma per
>+nuovi casi d'uso si dovrebbero usare meccanismi diversi, come mutex e
>+completion.
>+
>+semaphore e PREEMPT_RT
>+----------------------
>+
>+I kernel PREEMPT_RT non cambiano l'implementazione di semaphore perché non hanno
>+un concetto di proprietario, dunque impediscono a PREEMPT_RT d'avere
>+l'ereditarietà della priorità sui semafori. Un proprietario sconosciuto non può
>+ottenere una priorità superiore. Di consequenza, bloccarsi sui semafori porta
>+all'inversione di priorità.
>+
>+
>+rw_semaphore
>+============
>+
>+Il blocco rw_semaphore è un meccanismo che permette più lettori ma un solo scrittore.
>+
>+Sui kernel non-PREEMPT_RT l'implementazione è imparziale, quindi previene
>+l'inedia dei processi scrittori.
>+
>+Questi blocchi hanno una semantica molto stringente riguardo il proprietario, ma
>+offre anche interfacce speciali che permettono ai processi non proprietari di
>+rilasciare un processo lettore. Queste interfacce funzionano indipendentemente
>+dalla configurazione del kernel.
>+
>+rw_semaphore e PREEMPT_RT
>+-------------------------
>+
>+I kernel PREEMPT_RT sostituiscono i rw_semaphore con un'implementazione basata
>+su rt_mutex, e questo ne modifica l'imparzialità:
>+
>+ Dato che uno scrittore rw_semaphore non può assicurare la propria priorità ai
>+ suoi lettori, un lettore con priorità più bassa che ha subito la prelazione
>+ continuerà a trattenere il blocco, quindi porta all'inedia anche gli scrittori
>+ con priorità più alta. Per contro, dato che i lettori possono garantire la
>+ propria priorità agli scrittori, uno scrittore a bassa priorità che subisce la
>+ prelazione vedrà la propria priorità alzata finché non rilascerà il blocco, e
>+ questo preverrà l'inedia dei processi lettori a causa di uno scrittore.
>+
>+
>+local_lock
>+==========
>+
>+I local_lock forniscono nomi agli ambiti di visibilità delle sezioni critiche
>+protette tramite la disattivazione della prelazione o delle interruzioni.
>+
>+Sui kernel non-PREEMPT_RT le operazioni local_lock si traducono
>+nell'abilitazione o disabilitazione della prelazione o le interruzioni.
>+
>+ =============================== ======================
>+ local_lock(&llock) preempt_disable()
>+ local_unlock(&llock) preempt_enable()
>+ local_lock_irq(&llock) local_irq_disable()
>+ local_unlock_irq(&llock) local_irq_enable()
>+ local_lock_irqsave(&llock) local_irq_save()
>+ local_unlock_irqrestore(&llock) local_irq_restore()
>+ =============================== ======================
>+
>+Gli ambiti di visibilità con nome hanno due vantaggi rispetto alle primitive di
>+base:
>+
>+ - Il nome del blocco permette di fare un'analisi statica, ed è anche chiaro su
>+ cosa si applichi la protezione cosa che invece non si può fare con le
>+ classiche primitive in quanto sono opache e senza alcun ambito di
>+ visibilità.
>+
>+ - Se viene abilitato lockdep, allora local_lock ottiene un lockmap che
>+ permette di verificare la bontà della protezione. Per esempio, questo può
>+ identificare i casi dove una funzione usa preempt_disable() come meccanismo
>+ di protezione in un contesto d'interruzione (anche software). A parte
>+ questo, lockdep_assert_held(&llock) funziona come tutte le altre primitive
>+ di sincronizzazione.
>+
>+local_lock e PREEMPT_RT
>+-------------------------
>+
>+I kernel PREEMPT_RT sostituiscono local_lock con uno spinlock_t per CPU, quindi
>+ne cambia la semantica:
>+
>+ - Tutte le modifiche a spinlock_t si applicano anche a local_lock
>+
>+L'uso di local_lock
>+-------------------
>+
>+I local_lock dovrebbero essere usati su kernel non-PREEMPT_RT quando la
>+disabilitazione della prelazione o delle interruzioni è il modo più adeguato per
>+gestire l'accesso concorrente a strutture dati per CPU.
>+
>+Questo meccanismo non è adatto alla protezione da prelazione o interruzione su
>+kernel PREEMPT_RT dato che verrà convertito in spinlock_t.
>+
>+
>+raw_spinlock_t e spinlock_t
>+===========================
>+
>+raw_spinlock_t
>+--------------
>+
>+I blocco raw_spinlock_t è un blocco ad attesa attiva su tutti i tipi di kernel,
>+incluso quello PREEMPT_RT. Usate raw_spinlock_t solo in sezioni critiche nel
>+cuore del codice, nella gestione delle interruzioni di basso livello, e in posti
>+dove è necessario disabilitare la prelazione o le interruzioni. Per esempio, per
>+accedere in modo sicuro lo stato dell'hardware. A volte, i raw_spinlock_t
>+possono essere usati quando la sezione critica è minuscola, per evitare gli
>+eccessi di un rtmutex.
>+
>+spinlock_t
>+----------
>+
>+Il significato di spinlock_t cambia in base allo stato di PREEMPT_RT.
>+
>+Sui kernel non-PREEMPT_RT, spinlock_t si traduce in un raw_spinlock_t ed ha
>+esattamente lo stesso significato.
>+
>+spinlock_t e PREEMPT_RT
>+-----------------------
>+
>+Sui kernel PREEMPT_RT, spinlock_t ha un'implementazione dedicata che si basa
>+sull'uso di rt_mutex. Questo ne modifica il significato:
>+
>+ - La prelazione non viene disabilitata.
>+
>+ - I suffissi relativi alla interruzioni (_irq, _irqsave / _irqrestore) per le
>+ operazioni spin_lock / spin_unlock non hanno alcun effetto sullo stato delle
>+ interruzioni della CPU.
>+
>+ - I suffissi relativi alle interruzioni software (_bh()) disabilitano i
>+ relativi gestori d'interruzione.
>+
>+ I kernel non-PREEMPT_RT disabilitano la prelazione per ottenere lo stesso effetto.
>+
>+ I kernel PREEMPT_RT usano un blocco per CPU per la serializzazione, il che
>+ permette di tenere attiva la prelazione. Il blocco disabilita i gestori
>+ d'interruzione software e previene la rientranza vista la prelazione attiva.
>+
>+A parte quanto appena discusso, i kernel PREEMPT_RT preservano il significato
>+di tutti gli altri aspetti di spinlock_t:
>+
>+ - Le attività che trattengono un blocco spinlock_t non migrano su altri
>+ processori. Disabilitando la prelazione, i kernel non-PREEMPT_RT evitano la
>+ migrazione. Invece, i kernel PREEMPT_RT disabilitano la migrazione per
>+ assicurarsi che i puntatori a variabili per CPU rimangano validi anche
>+ quando un'attività subisce la prelazione.
>+
>+ - Lo stato di un'attività si mantiene durante le acquisizioni del blocco al
>+ fine di garantire che le regole basate sullo stato delle attività si possano
>+ applicare a tutte le configurazioni del kernel. I kernel non-PREEMPT_RT
>+ lasciano lo stato immutato. Tuttavia, la funzionalità PREEMPT_RT deve
>+ cambiare lo stato se l'attività si blocca durante l'acquisizione. Dunque,
>+ salva lo stato attuale prima di bloccarsi ed il rispettivo risveglio lo
>+ ripristinerà come nell'esempio seguente::
>+
>+ task->state = TASK_INTERRUPTIBLE
>+ lock()
>+ block()
>+ task->saved_state = task->state
>+ task->state = TASK_UNINTERRUPTIBLE
>+ schedule()
>+ lock wakeup
>+ task->state = task->saved_state
>+
>+ Altri tipi di risvegli avrebbero impostato direttamente lo stato a RUNNING,
>+ ma in questo caso non avrebbe funzionato perché l'attività deve rimanere
>+ bloccata fintanto che il blocco viene trattenuto. Quindi, lo stato salvato
>+ viene messo a RUNNING quando il risveglio di un non-blocco cerca di
>+ risvegliare un'attività bloccata in attesa del rilascio di uno spinlock. Poi,
>+ quando viene completata l'acquisizione del blocco, il suo risveglio
>+ ripristinerà lo stato salvato, in questo caso a RUNNING::
>+
>+ task->state = TASK_INTERRUPTIBLE
>+ lock()
>+ block()
>+ task->saved_state = task->state
>+ task->state = TASK_UNINTERRUPTIBLE
>+ schedule()
>+ non lock wakeup
>+ task->saved_state = TASK_RUNNING
>+
>+ lock wakeup
>+ task->state = task->saved_state
>+
>+ Questo garantisce che il vero risveglio non venga perso.
>+
>+rwlock_t
>+========
>+
>+Il blocco rwlock_t è un meccanismo che permette più lettori ma un solo scrittore.
>+
>+Sui kernel non-PREEMPT_RT questo è un blocco ad attesa e per i suoi suffissi si
>+applicano le stesse regole per spinlock_t. La sua implementazione è imparziale,
>+quindi previene l'inedia dei processi scrittori.
>+
>+rwlock_t e PREEMPT_RT
>+---------------------
>+
>+Sui kernel PREEMPT_RT rwlock_t ha un'implementazione dedicata che si basa
>+sull'uso di rt_mutex. Questo ne modifica il significato:
>+
>+ - Tutte le modifiche fatte a spinlock_t si applicano anche a rwlock_t.
>+
>+ - Dato che uno scrittore rw_semaphore non può assicurare la propria priorità ai
>+ suoi lettori, un lettore con priorità più bassa che ha subito la prelazione
>+ continuerà a trattenere il blocco, quindi porta all'inedia anche gli
>+ scrittori con priorità più alta. Per contro, dato che i lettori possono
>+ garantire la propria priorità agli scrittori, uno scrittore a bassa priorità
>+ che subisce la prelazione vedrà la propria priorità alzata finché non
>+ rilascerà il blocco, e questo preverrà l'inedia dei processi lettori a causa
>+ di uno scrittore.
>+
>+
>+Precisazioni su PREEMPT_RT
>+==========================
>+
>+local_lock su RT
>+----------------
>+
>+Sui kernel PREEMPT_RT Ci sono alcune implicazioni dovute alla conversione di
>+local_lock in un spinlock_t. Per esempio, su un kernel non-PREEMPT_RT il
>+seguente codice funzionerà come ci si aspetta::
>+
>+ local_lock_irq(&local_lock);
>+ raw_spin_lock(&lock);
>+
>+ed è equivalente a::
>+
>+ raw_spin_lock_irq(&lock);
>+
>+Ma su un kernel PREEMPT_RT questo codice non funzionerà perché local_lock_irq()
>+si traduce in uno spinlock_t per CPU che non disabilita né le interruzioni né la
>+prelazione. Il seguente codice funzionerà su entrambe i kernel con o senza
>+PREEMPT_RT::
>+
>+ local_lock_irq(&local_lock);
>+ spin_lock(&lock);
>+
>+Un altro dettaglio da tenere a mente con local_lock è che ognuno di loro ha un
>+ambito di protezione ben preciso. Dunque, la seguente sostituzione è errate::
>+
>+
>+ func1()
>+ {
>+ local_irq_save(flags); -> local_lock_irqsave(&local_lock_1, flags);
>+ func3();
>+ local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_1, flags);
>+ }
>+
>+ func2()
>+ {
>+ local_irq_save(flags); -> local_lock_irqsave(&local_lock_2, flags);
>+ func3();
>+ local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_2, flags);
>+ }
>+
>+ func3()
>+ {
>+ lockdep_assert_irqs_disabled();
>+ access_protected_data();
>+ }
>+
>+Questo funziona correttamente su un kernel non-PREEMPT_RT, ma su un kernel
>+PREEMPT_RT local_lock_1 e local_lock_2 sono distinti e non possono serializzare
>+i chiamanti di func3(). L'*assert* di lockdep verrà attivato su un kernel
>+PREEMPT_RT perché local_lock_irqsave() non disabilita le interruzione a casa
>+della specifica semantica di spinlock_t in PREEMPT_RT. La corretta sostituzione
>+è::
>+
>+ func1()
>+ {
>+ local_irq_save(flags); -> local_lock_irqsave(&local_lock, flags);
>+ func3();
>+ local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flags);
>+ }
>+
>+ func2()
>+ {
>+ local_irq_save(flags); -> local_lock_irqsave(&local_lock, flags);
>+ func3();
>+ local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flags);
>+ }
>+
>+ func3()
>+ {
>+ lockdep_assert_held(&local_lock);
>+ access_protected_data();
>+ }
>+
>+spinlock_t e rwlock_t
>+---------------------
>+
>+Ci sono alcune conseguenze di cui tener conto dal cambiamento di semantica di
>+spinlock_t e rwlock_t sui kernel PREEMPT_RT. Per esempio, sui kernel non
>+PREEMPT_RT il seguente codice funziona come ci si aspetta::
>+
>+ local_irq_disable();
>+ spin_lock(&lock);
>+
>+ed è equivalente a::
>+
>+ spin_lock_irq(&lock);
>+
>+Lo stesso vale per rwlock_t e le varianti con _irqsave().
>+
>+Sui kernel PREEMPT_RT questo codice non funzionerà perché gli rtmutex richiedono
>+un contesto con la possibilità di prelazione. Al suo posto, usate
>+spin_lock_irq() o spin_lock_irqsave() e le loro controparti per il rilascio. I
>+kernel PREEMPT_RT offrono un meccanismo local_lock per i casi in cui la
>+disabilitazione delle interruzioni ed acquisizione di un blocco devono rimanere
>+separati. Acquisire un local_lock àncora un processo ad una CPU permettendo cose
>+come un'acquisizione di un blocco con interruzioni disabilitate per singola CPU.
>+
>+Il tipico scenario è quando si vuole proteggere una variabile di processore nel
>+contesto di un thread::
>+
>+
>+ struct foo *p = get_cpu_ptr(&var1);
>+
>+ spin_lock(&p->lock);
>+ p->count += this_cpu_read(var2);
>+
>+Questo codice è corretto su un kernel non-PREEMPT_RT, ma non lo è su un
>+PREEMPT_RT. La modifica della semantica di spinlock_t su PREEMPT_RT non permette
>+di acquisire p->lock perché, implicitamente, get_cpu_ptr() disabilita la
>+prelazione. La seguente sostituzione funzionerà su entrambe i kernel::
>+
>+ struct foo *p;
>+
>+ migrate_disable();
>+ p = this_cpu_ptr(&var1);
>+ spin_lock(&p->lock);
>+ p->count += this_cpu_read(var2);
>+
>+La funzione migrate_disable() assicura che il processo venga tenuto sulla CPU
>+corrente, e di conseguenza garantisce che gli accessi per-CPU alle variabili var1 e
>+var2 rimangano sulla stessa CPU fintanto che il processo rimane prelabile.
>+
>+La sostituzione con migrate_disable() non funzionerà nel seguente scenario::
>+
>+ func()
>+ {
>+ struct foo *p;
>+
>+ migrate_disable();
>+ p = this_cpu_ptr(&var1);
>+ p->val = func2();
>+
>+Questo non funziona perché migrate_disable() non protegge dal ritorno da un
>+processo che aveva avuto il diritto di prelazione. Una sostituzione più adatta
>+per questo caso è::
>+
>+ func()
>+ {
>+ struct foo *p;
>+
>+ local_lock(&foo_lock);
>+ p = this_cpu_ptr(&var1);
>+ p->val = func2();
>+
>+Su un kernel non-PREEMPT_RT, questo codice protegge dal rientro disabilitando la
>+prelazione. Su un kernel PREEMPT_RT si ottiene lo stesso risultato acquisendo lo
>+spinlock di CPU.
>+
>+raw_spinlock_t su RT
>+--------------------
>+
>+Acquisire un raw_spinlock_t disabilita la prelazione e possibilmente anche le
>+interruzioni, quindi la sezione critica deve evitare di acquisire uno spinlock_t
>+o rwlock_t. Per esempio, la sezione critica non deve fare allocazioni di
>+memoria. Su un kernel non-PREEMPT_RT il seguente codice funziona perfettamente::
>+
>+ raw_spin_lock(&lock);
>+ p = kmalloc(sizeof(*p), GFP_ATOMIC);
>+
>+Ma lo stesso codice non funziona su un kernel PREEMPT_RT perché l'allocatore di
>+memoria può essere oggetto di prelazione e quindi non può essere chiamato in un
>+contesto atomico. Tuttavia, si può chiamare l'allocatore di memoria quando si
>+trattiene un blocco *non-raw* perché non disabilitano la prelazione sui kernel
>+PREEMPT_RT::
>+
>+ spin_lock(&lock);
>+ p = kmalloc(sizeof(*p), GFP_ATOMIC);
>+
>+
>+bit spinlocks
>+-------------
>+
>+I kernel PREEMPT_RT non possono sostituire i bit spinlock perché un singolo bit
>+è troppo piccolo per farci stare un rtmutex. Dunque, la semantica dei bit
>+spinlock è mantenuta anche sui kernel PREEMPT_RT. Quindi, le precisazioni fatte
>+per raw_spinlock_t valgono anche qui.
>+
>+In PREEMPT_RT, alcuni bit spinlock sono sostituiti con normali spinlock_t usando
>+condizioni di preprocessore in base a dove vengono usati. Per contro, questo non
>+serve quando si sostituiscono gli spinlock_t. Invece, le condizioni poste sui
>+file d'intestazione e sul cuore dell'implementazione della sincronizzazione
>+permettono al compilatore di effettuare la sostituzione in modo trasparente.
>+
>+
>+Regole d'annidamento dei tipi di blocchi
>+========================================
>+
>+Le regole principali sono:
>+
>+ - I tipi di blocco appartenenti alla stessa categoria possono essere annidati
>+ liberamente a patto che si rispetti l'ordine di blocco al fine di evitare
>+ stalli.
>+
>+ - I blocchi con sospensione non possono essere annidati in blocchi del tipo
>+ CPU locale o ad attesa attiva
>+
>+ - I blocchi ad attesa attiva e su CPU locale possono essere annidati nei
>+ blocchi ad attesa con sospensione.
>+
>+ - I blocchi ad attesa attiva possono essere annidati in qualsiasi altro tipo.
>+
>+Queste limitazioni si applicano ad entrambe i kernel con o senza PREEMPT_RT.
>+
>+Il fatto che un kernel PREEMPT_RT cambi i blocchi spinlock_t e rwlock_t dal tipo
>+ad attesa attiva a quello con sospensione, e che sostituisca local_lock con uno
>+spinlock_t per CPU, significa che non possono essere acquisiti quando si è in un
>+blocco raw_spinlock. Ne consegue il seguente ordine d'annidamento:
>+
>+ 1) blocchi ad attesa con sospensione
>+ 2) spinlock_t, rwlock_t, local_lock
>+ 3) raw_spinlock_t e bit spinlocks
>+
>+Se queste regole verranno violate, allora lockdep se ne accorgerà e questo sia
>+con o senza PREEMPT_RT.
>--
>2.39.2
>
--
Federico Vaga
Powered by blists - more mailing lists