From nobody Fri Dec 26 09:19:13 2025 Received: from mx.kolabnow.com (mx.kolabnow.com [212.103.80.153]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EB6AD10787; Sat, 6 Jan 2024 23:47:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=vaga.pv.it Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=vaga.pv.it Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=kolabnow.com header.i=@kolabnow.com header.b="jWRfSFSz" Received: from localhost (unknown [127.0.0.1]) by mx.kolabnow.com (Postfix) with ESMTP id 5BEEA2096F1E; Sun, 7 Jan 2024 00:38:52 +0100 (CET) Authentication-Results: ext-mx-out011.mykolab.com (amavis); dkim=pass (4096-bit key) reason="pass (just generated, assumed good)" header.d=kolabnow.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kolabnow.com; h= content-transfer-encoding:content-type:content-type:mime-version :message-id:date:date:subject:subject:from:from:received :received:received; s=dkim20160331; t=1704584326; x=1706398727; bh=fFiHVho2Q137ByuhwvZm3I4hvXZuxjEuzbnbTkF0fuc=; b=jWRfSFSzBVEC cEWaXVdzZParmpMnYE7jjLP4C2re6uiDM/xthjK3msc7IoDb8tYEaIEiL9PPSdIM I6KInfearJ8OvymqI+bAiYSlQ0VtiYLcD7SxG5JMDyG4tinNvUHcnUmJKQXG4pRf kFiGuAQ/o/+HifbtPVquJdzrKolzRE+4de22pK1paHkpZUwB24IAu+vDY0on2h/e FVpNPi7/T0xgQW6yGhkja8H7/C7aqoOlLqt7z2eZoWx/Wdq0M4nNcZ1AcBBogMCH Nl5hXwZi1n5/r3MDbsVN8hlSerhmP1rHSI2BVKG60eTSeVAVTKkeOZFE8EAnRu2M vqPs2T4L4lB28QUx9Ib1XhHjsMjlyw+bLFYABRyhLTmPKpG7jPYZ1u7dTpazWRig r2TkJSEj50MOomhMAydxe4kMLQbx2BvK+MNICFkIr8IJHlrvhKhWsbnSYTeOPjBS tidHxZJc3C1ov1W+KdkefsKhuZp5rWsTLizOc2raIPudfuatxey6HrFZK30T3XRi tbGPsw/n3mOXDJFFZpNgOmHEYlOjRejKav61T4XWTHJ6gagabfXGaINYDDvRgN3k tR6OmgHhdVCuyl0PO8/xfMHHN8Ne407mKpDEj9nxGgRSvuXbRdChmUfq8hxGWv/V OdT7Bla8m4RFAepIKiPUB+BVp8Y22CE= X-Virus-Scanned: amavis at mykolab.com X-Spam-Flag: NO X-Spam-Score: -1 X-Spam-Level: Received: from mx.kolabnow.com ([127.0.0.1]) by localhost (ext-mx-out011.mykolab.com [127.0.0.1]) (amavis, port 10024) with ESMTP id xI5u-C_a8Pyk; Sun, 7 Jan 2024 00:38:46 +0100 (CET) Received: from int-mx009.mykolab.com (unknown [10.9.13.9]) by mx.kolabnow.com (Postfix) with ESMTPS id A7B2920C73FF; Sun, 7 Jan 2024 00:38:44 +0100 (CET) Received: from ext-subm010.mykolab.com (unknown [10.9.6.10]) by int-mx009.mykolab.com (Postfix) with ESMTPS id AB04C25AB8A0; Sun, 7 Jan 2024 00:38:44 +0100 (CET) From: Federico Vaga To: Jonathan Corbet Cc: Federico Vaga , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] doc:it_IT: first translation for locking/ Date: Sun, 7 Jan 2024 00:38:20 +0100 Message-Id: <20240106233820.30454-1-federico.vaga@vaga.pv.it> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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 --- 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 t= his directory:: =20 tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28 =20 -Then this run can be re-run without rebuilding as follow: +Then this run can be re-run without rebuilding as follow:: =20 kvm-again.sh tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28 =20 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: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Concetti su RCU +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. toctree:: + :maxdepth: 3 + + torture + +.. only:: subproject and html + + Indici + =3D=3D=3D=3D=3D=3D + + * :ref:`genindex` diff --git a/Documentation/translations/it_IT/RCU/torture.rst b/Documentati= on/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 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Le operazioni RCU per le verifiche *torture* +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +CONFIG_RCU_TORTURE_TEST +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +L'opzione CONFIG_RCU_TORTURE_TEST =C3=A8 disponibile per tutte le implemen= tazione di +RCU. L'opzione creer=C3=A0 un modulo rcutorture che potrete caricare per a= vviare le +verifiche. La verifica user=C3=A0 printk() per riportare lo stato, dunque = potrete +visualizzarlo con dmesg (magari usate grep per filtrare "torture"). Le ver= ifiche +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 +=3D=3D=3D=3D=3D=3D=3D=3D + +Il rapporto sulle verifiche si presenta nel seguente modo:: + + rcu-torture:--- Start of test: nreaders=3D16 nfakewriters=3D4 stat_interv= al=3D30 verbose=3D0 test_no_idle_hz=3D1 shuffle_interval=3D3 stutter=3D5 ir= qreader=3D1 fqs_duration=3D0 fqs_holdoff=3D0 fqs_stutter=3D3 test_boost=3D1= /0 test_boost_interval=3D7 test_boost_duration=3D4 + 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: 3055= 767 + 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=3D16 nfakewriters=3D4 stat= _interval=3D30 verbose=3D0 test_no_idle_hz=3D1 shuffle_interval=3D3 stutter= =3D5 irqreader=3D1 fqs_duration=3D0 fqs_holdoff=3D0 fqs_stutter=3D3 test_bo= ost=3D1/0 test_boost_interval=3D7 test_boost_duration=3D4 + +Sulla maggior parte dei sistemi questo rapporto si produce col comando "dm= esg | +grep torture:". Su configurazioni pi=C3=B9 esoteriche potrebbe essere nece= ssario +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 s= olo +sull'ultima riga abbiamo il risultato finale delle verifiche effettuate ch= e pu=C3=B2 +essere "SUCCESS" (successo) or "FAILURE" (insuccesso). + +Le voci sono le seguenti: + +* "rtc": L'indirizzo in esadecimale della struttura attualmente visibile d= ai + lettori. + +* "ver": Il numero di volte dall'avvio che il processo scrittore di RCU ha + cambiato la struttura visible ai lettori. + +* "tfle": se non =C3=A8 zero, indica la lista di strutture "torture freeli= st" da + mettere in "rtc" =C3=A8 vuota. Questa condizione =C3=A8 importante perch= =C3=A9 potrebbe + illuderti che RCU stia funzionando mentre invece non =C3=A8 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 =C3=A8 inusuale che sia diverso da = zero, ma =C3=A8 + 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 =C3=A8 stato capace di creare dei kthread real-time = per forzare + l'inversione di priorit=C3=A0 di RCU. Il valore dovrebbe essere zero. + +* "rtbre": sebbene rcutorture sia riuscito a creare dei kthread capaci di + forzare l'inversione di priorit=C3=A0, non =C3=A8 riuscito per=C3=B2 ad = impostarne la + priorit=C3=A0 real-time al livello 1. Il valore dovrebbe essere zero. + +* "rtbf": Il numero di volte che =C3=A8 fallita la promozione della priori= t=C3=A0 per + risolvere un'inversione. + +* "rtb": Il numero di volte che rcutorture ha provato a forzare l'inversio= ne di + priorit=C3=A0. Il valore dovrebbe essere diverso da zero Se state verifi= cando la + promozione della priorit=C3=A0 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 dive= rso da + zero se avete specificato il parametro "irqreader". + +* "Reader Pipe": un istogramma dell'et=C3=A0 delle strutture viste dai let= tori. RCU + non funziona correttamente se una qualunque voce, dalla terza in poi, ha= un + valore diverso da zero. Se dovesse succedere, rcutorture stampa la strin= ga + "!!!" per renderlo ben visibile. L'et=C3=A0 di una struttura appena crea= ta =C3=A8 zero, + diventer=C3=A0 uno quando sparisce dalla visibilit=C3=A0 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 =C3=A8 stata presa da una corretta implementazion= e di RCU. + Se volete vedere come appare quando non funziona, sbizzarritevi nel romp= erla. + ;-) + +* "Reader Batch": un istogramma di et=C3=A0 di strutture viste dai lettori= , ma + conteggiata in termini di lotti piuttosto che periodi. Anche qui dalla t= erza + voce in poi devono essere zero. La ragione d'esistere di questo rapporto= =C3=A8 che + a volte =C3=A8 pi=C3=B9 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 rag= giunto + un certo punto nella catena. Il primo numero dovrebbe corrispondere + strettamente al numero di strutture allocate; il secondo conta quelle ri= mosse + dalla vista dei lettori. Ad eccezione dell'ultimo valore, gli altri + corrispondono al numero di passaggi attraverso il periodo di grazia. L'u= ltimo + valore dovrebbe essere zero, perch=C3=A9 viene incrementato solo se il c= ontatore + della struttura torture viene in un qualche modo incrementato oltre il + normale. + +Una diversa implementazione di RCU potrebbe fornire informazioni aggiuntiv= e. Per +esempio, *Tree SRCU* fornisce anche la seguente riga:: + + srcud-torture: Tree SRCU per-CPU(idx=3D0): 0(35,-21) 1(-4,24) 2(1,1) 3(-2= 6,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 p= er +*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 =C3=A8 utile per il *debug*. La "T" final= e contiene +il valore totale dei contatori. + +Uso su specifici kernel +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +A volte pu=C3=B2 essere utile eseguire RCU torture su un kernel gi=C3=A0 c= ompilato, ad +esempio quando lo si sta per mettere in proeduzione. In questo caso, il ke= rnel +dev'essere compilato con CONFIG_RCU_TORTUE_TEST=3Dm, cosicch=C3=A9 le veri= fiche 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 mar= catore +di errore "!!!". Ovviamente, siete liberi di scriverne uno pi=C3=B9 elabor= ato 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 problem= i in +RCU, tuttavia ci sono stati problemi con CPU-hotplug. + + +Uso sul kernel di riferimento +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + +Quando si usa rcutorture per verificare modifiche ad RCU stesso, spesso = =C3=A8 +necessario compilare un certo numero di kernel usando configurazioni diver= se e +con parametri d'avvio diversi. In questi casi, usare modprobe ed rmmod pot= rebbe +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, arm= 64 e +powerpc. Di base, eseguir=C3=A0 la serie di verifiche elencate in +tools/testing/selftests/rcutorture/configs/rcu/CFLIST. Ognuna di queste ve= rr=C3=A0 +eseguita per 30 minuti in una macchina virtuale con uno spazio utente mini= male +fornito da un initrd generato automaticamente. Al completamento, gli artef= atti +prodotti e i messaggi vengono analizzati alla ricerca di errori, ed i risu= ltati +delle esecuzioni riassunti in un rapporto. + +Su grandi sistemi, le verifiche di rcutorture posso essere velocizzare pas= sano a +kvm.sh l'argomento --cpus. Per esempio, su un sistema a 64 processori, "--= cpus +43" user=C3=A0 fino a 43 processori per eseguire contemporaneamente le ver= ifiche. 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 se= dici +kernel). L'argomento "--dryrun sched" non eseguir=C3=A0 verifiche, piuttos= to vi +informer=C3=A0 su come queste verranno organizzate in serie. Questo pu=C3= =B2 essere utile +per capire quanti processori riservare per le verifiche in --cpus. + +Non serve eseguire tutti gli scenari di verifica per ogni modifica. Per es= empio, +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 'SR= CU-N +SRCU-P'". Su grandi sistemi si possono eseguire pi=C3=B9 copie degli stess= i scenari, +per esempio, un hardware che permette di eseguire 448 thread, pu=C3=B2 ese= guire 5 +istanze complete contemporaneamente. Per farlo:: + + kvm.sh --cpus 448 --configs '5*CFLIST' + +Oppure, lo stesso sistema, pu=C3=B2 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=C3=A0 della memoria. Potete limitarn= e l'uso con +l'argomento --memory, che di base assume il valore 512M. Per poter usare v= alori +piccoli dovrete disabilitare le verifiche *callback-flooding* usando il +parametro --bootargs che vedremo in seguito. + +A volte =C3=A8 utile avere informazioni aggiuntive di debug, in questo cas= o potete +usare il parametro --kconfig, per esempio, ``--kconfig +'CONFIG_RCU_EQS_DEBUG=3Dy'``. In aggiunta, ci sono i parametri --gdb, --ka= san, and +kcsan. Da notare che --gdb vi limiter=C3=A0 all'uso di un solo scenario per +esecuzione di kvm.sh e richiede di avere anche un'altra finestra aperta da= lla +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=3D30``. Il programma riporter=C3=A0 un fallimento, o= ssia il +risultato della verifica. Come visto in precedenza, ridurre la memoria ric= hiede +la disabilitazione delle verifiche *callback-flooding*:: + + kvm.sh --cpus 448 --configs '56*TREE04' --memory 128M \ + --bootargs 'rcutorture.fwd_progress=3D0' + +A volte tutto quello che serve =C3=A8 una serie completa di compilazioni d= el kernel. +Questo si ottiene col parametro --buildonly. + +Il parametro --duration sovrascrive quello di base di 30 minuti. Per esemp= io, +con ``--duration 2d`` l'esecuzione sar=C3=A0 di due giorni, ``--duraction = 5min`` di +cinque minuti, e ``--duration 45s`` di 45 secondi. L'ultimo pu=C3=B2 esser= e 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 sen= za il +parametro --trust-make, i vostri file di *tag* potrebbero essere distrutti. + +Ci sono altri parametri pi=C3=B9 misteriosi che sono documentati nel codic= e sorgente +dello programma kvm.sh. + +Se un'esecuzione contiene degli errori, il loro numero durante la compilaz= ione 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 da= lla +compilazione ed i risultati stampati vengono salvati, usando un riferimento +temporale, nelle cartella tools/testing/selftests/rcutorture/res. Una cart= ella +di queste cartelle pu=C3=B2 essere fornita a kvm-find-errors.sh per estrar= ne 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 =C3=A8 pi=C3=B9 conveniente aprire i file direttame= nte. 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 d= ello +scenario stesso (per esempio, "TREE04"). Se un dato scenario viene eseguit= o pi=C3=B9 +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=C3=B9 usato nella cartella principale =C3=A8 testid= .txt. Se la +verifica viene eseguita in un repositorio git, allora questo file conterr= =C3=A0 il +*commit* sul quale si basano le verifiche, mentre tutte le modifiche non +registrare verranno mostrate in formato diff. + +I file solitamente pi=C3=B9 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 scen= ario + +console.log + Questo file contiene il risultato d'esecuzione per uno specifico scenari= o. + Questo file pu=C3=B2 essere esaminato una volta che il kernel =C3=A8 sta= to avviato, + ma potrebbe non esistere se l'avvia non =C3=A8 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 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Immaginate di essere alla caccia di un raro problema che si verifica all'a= vvio. +Potreste usare kvm.sh, tuttavia questo ricompilerebbe il kernel ad ogni +esecuzione. Se avete bisogno di (diciamo) 1000 esecuzioni per essere sicur= i di +aver risolto il problema, allora queste inutili ricompilazioni possono div= entare +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=C3=B2 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 aiutand= o a +trovare quel raro problema all'avvio sopracitato. + +Esecuzioni distribuite +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Sebbene kvm.sh sia utile, le sue verifiche sono limitate ad un singolo sis= tema. +Non =C3=A8 poi cos=C3=AC 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 distribuzio= ne +degli scenari di verifica per rcutorture sui sistemi disponibili richiede +scrupolo perch=C3=A9 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=C3=A0 lo scenario di base sul sistema locale, poi lo distr= ibuir=C3=A0 agli +altri cinque sistemi elencati fra i parametri, ed eseguir=C3=A0 ogni scena= rio per +otto ore. Alla fine delle esecuzioni, i risultati verranno raccolti, regis= trati, +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=C3=B2 essere utile per sco= prire +quanti scenari potrebbero essere eseguiti in gruppo di sistemi. + +Potete rieseguire anche una precedente esecuzione remota come abbiamo gi= =C3=A0 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 ess= ere +usati dopo il percorso alla cartella contenente gli artefatti dell'esecuzi= one da +ripetere. diff --git a/Documentation/translations/it_IT/core-api/index.rst b/Document= ation/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=C3=A0 di base =20 symbol-namespaces =20 +Primitive di sincronizzazione +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + +Come Linux impedisce che tutto si verifichi contemporaneamente. Consultate +Documentation/translations/it_IT/locking/index.rst per maggiorni informazi= oni +sul tema. + +.. toctree:: + :maxdepth: 1 + + ../RCU/index + .. only:: subproject and html =20 Indices diff --git a/Documentation/translations/it_IT/index.rst b/Documentation/tra= nslations/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 =20 core-api/index + Sincronizzazione nel kernel =20 Strumenti e processi per lo sviluppo =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D diff --git a/Documentation/translations/it_IT/locking/index.rst b/Documenta= tion/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 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Sincronizzazione +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. toctree:: + :maxdepth: 1 + + locktypes + lockdep-design + lockstat + locktorture + +.. only:: subproject and html + + Indici + =3D=3D=3D=3D=3D=3D + + * :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 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +Classi di blocchi +----------------- + +L'oggetto su cui il validatore lavora =C3=A8 una "classe" di blocchi. + +Una classe di blocchi =C3=A8 un gruppo di blocchi che seguono le stesse re= gole di +sincronizzazione, anche quando i blocchi potrebbero avere pi=C3=B9 istanze= (anche +decine di migliaia). Per esempio un blocco nella struttura inode =C3=A8 un= a classe, +mentre ogni inode sar=C3=A0 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 vi= ene +usato rispetto al suo contesto d'interruzione, mentre le dipendenze di un = blocco +possono essere interpretate come il loro ordine; per esempio L1 -> L2 sugg= erisce +che un processo cerca di acquisire L2 mentre gi=C3=A0 trattiene L1. Dal pu= nto di +vista di lockdep, i due blocchi (L1 ed L2) non sono per forza correlati: q= uella +dipendenza indica solamente l'ordine in cui sono successe le cose. Il vali= datore +verifica permanentemente la correttezza dell'uso dei blocchi e delle loro +dipendenze, altrimenti ritorner=C3=A0 un errore. + +Il comportamento di una classe di blocchi viene costruito dall'insieme del= le sue +istanze. Una classe di blocco viene registrata alla creazione della sua pr= ima +istanza, mentre tutte le successive istanze verranno mappate; dunque, il l= oro +uso e le loro dipendenze contribuiranno a costruire quello della classe. U= na +classe di blocco non sparisce quando sparisce una sua istanza, ma pu=C3=B2= essere +rimossa quando il suo spazio in memoria viene reclamato. Per esempio, ques= to +succede quando si rimuove un modulo, o quando una *workqueue* viene elimin= ata. + +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 ' +- 'sempre trattenuto come blocco di lettura nel contesto ' +- 'sempre trattenuto con abilitato' +- 'sempre trattenuto come blocco di lettura con abilitato' + +gli `n` STATI sono codificati in kernel/locking/lockdep_states.h, ad oggi +includono: + +- hardirq +- softirq + +infine l'ultima categoria =C3=A8: + +- 'sempre trattenuto' [ =3D=3D !unused = ] + +Quando vengono violate le regole di sincronizzazione, questi bit di utiliz= zo +vengono presentati nei messaggi di errore di sincronizzazione, fra parente= si +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: [] mutex_lock+0x21/0x24 + + but task is already holding lock: + (&sio_locks[i].lock){-.-.}, at: [] 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: + + =3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + '.' acquisito con interruzioni disabilitate fuori da un contesto d'int= erruzione + '-' acquisito in contesto d'interruzione + '+' acquisito con interruzioni abilitate + '?' acquisito in contesto d'interruzione con interruzioni abilitate + =3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + +Il seguente esempio mostra i bit:: + + (&sio_locks[i].lock){-.-.}, at: [] mutex_lock+0x21/0x24 + |||| + ||| \-> softirq disabilitati e fuori da un contes= to di softirq + || \--> acquisito in un contesto di softirq + | \---> hardirq disabilitati e fuori da un contes= to 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 scena= ri +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=C3= =A9 +altrimenti verrebbe mostrato il carattere '?'. Una deduzione simile pu=C3= =B2 essere +fatta anche per '+' + +I blocchi inutilizzati (ad esempio i mutex) non possono essere fra le caus= e di +un errore. + +Regole dello stato per un blocco singolo +---------------------------------------- + +Avere un blocco sicuro in interruzioni (*irq-safe*) significa che =C3=A8 s= empre stato +usato in un contesto d'interruzione, mentre un blocco insicuro in interruz= ioni +(*irq-unsafe*) significa che =C3=A8 sempre stato acquisito con le interruz= ioni +abilitate. + +Una classe softirq insicura =C3=A8 automaticamente insicura anche per hard= irq. I +seguenti stati sono mutualmente esclusivi: solo una pu=C3=B2 essere vero q= uando viene +usata una classe di blocco:: + + o + o + +Questo perch=C3=A9 se un blocco pu=C3=B2 essere usato in un contesto di in= terruzioni +(sicuro in interruzioni), allora non pu=C3=B2 mai essere acquisito con le +interruzioni abilitate (insicuro in interruzioni). Altrimenti potrebbe +verificarsi uno stallo. Per esempio, questo blocco viene acquisito, ma pri= ma di +essere rilasciato il contesto d'esecuzione viene interrotto nuovamente, e = quindi +si tenter=C3=A0 di acquisirlo nuovamente. Questo porter=C3=A0 ad uno stall= o, in +particolare uno stallo ricorsivo. + +Il validatore rileva e riporta gli usi di blocchi che violano queste regol= e per +blocchi singoli. + +Regole per le dipendenze di blocchi multipli +-------------------------------------------- + +La stessa classe di blocco non deve essere acquisita due volte, questo per= ch=C3=A9 +potrebbe portare ad uno blocco ricorsivo e dunque ad uno stallo. + +Inoltre, due blocchi non possono essere trattenuti in ordine inverso:: + + -> + -> + +perch=C3=A9 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 =C3=A8 in grado di= trovare +queste dipendenze cicliche di qualsiasi complessit=C3=A0, ovvero nel mezzo= ci +potrebbero essere altre sequenze di blocchi. Il validatore trover=C3=A0 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:: + + -> + -> + +La prima regola deriva dal fatto che un blocco sicuro in interruzioni pu= =C3=B2 essere +trattenuto in un contesto d'interruzione che, per definizione, ha la possi= bilit=C3=A0 +di interrompere un blocco insicuro in interruzioni; questo porterebbe ad u= no +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: qu= ando +si acquisiscono nuovi blocchi, il validatore verifica se vi =C3=A8 una vio= lazione +delle regole fra il nuovo blocco e quelli gi=C3=A0 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=C3=A9 un contesto d'interr= uzione +potrebbe interrompere l'esecuzione di qualsiasi blocco insicuro portando a= d 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=C3=B9 volte la st= essa +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=C3=A0 d= i questa +gerarchia), ed il kernel tratterr=C3=A0 i blocchi in questo ordine prefiss= ato 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 =C3=A8 una parte del disco intero, e l'ordin= e dei +blocchi sar=C3=A0 corretto fintantoche uno acquisisce il blocco del disco = intero e +poi quello della partizione. Il validatore non rileva automaticamente ques= to +ordine implicito, perch=C3=A9 queste regole di sincronizzazione non sono s= tatiche. + +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 c= he si +tratta di una partizione. + +Ai fini della validazione, il validatore lo considerer=C3=A0 con una - sot= to - classe +di blocco separata. + +Nota: Prestate estrema attenzione che la vostra gerarchia sia corretta qua= ndo 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 bl= occhi +devono essere trattenuti: lockdep_assert_held*(&lock) e +lockdep_*pin_lock(&lock). + +Come suggerito dal nome, la famiglia di macro lockdep_assert_held* asseris= cono +che un dato blocco in un dato momento deve essere trattenuto (altrimenti, = verr=C3=A0 +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 =C3=A8 necessario per aggiornare in sicurezz= a il clock +rq. + +L'altra famiglia di macro =C3=A8 lockdep_*pin_lock(), che a dire il vero v= iene 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 de= ve +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_l= ock() +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 =3D 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 uti= li, +tuttavia sono le verifiche in esecuzione effettuate da queste macro ad ess= ere +vitali per scovare problemi di sincronizzazione, ed inoltre forniscono lo = stesso +livello di informazioni quando si ispeziona il codice. Nel dubbio, preferi= te +queste annotazioni! + +Dimostrazione di correttezza al 100% +------------------------------------ + +Il validatore verifica la propriet=C3=A0 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=C3=A0 con una certezza del 1= 00% che +nessuna combinazione e tempistica di queste sequenze possa causare uno sta= llo 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 validato= re pu=C3=B2 +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=C3= =B2 essere +riprodotto su un sistema a singolo processore. + +Questo riduce drasticamente la complessit=C3=A0 del controllo di qualit=C3= =A0 della +sincronizzazione nel kernel: quello che deve essere fatto =C3=A8 di innesc= are nel +kernel quante pi=C3=B9 possibili "semplici" sequenze di sincronizzazione, = almeno una +volta, allo scopo di dimostrarne la correttezza. Questo al posto di innesc= are +una verifica per ogni possibile combinazione di sincronizzazione fra proce= ssori, +e differenti scenari con hardirq e softirq e annidamenti vari (nella prati= ca, +impossibile da fare) + +.. [1] + + assumendo che il validatore sia corretto al 100%, e che nessun altra pa= rte + del sistema possa corromperne lo stato. Assumiamo anche che tutti i per= corsi + MNI/SMM [potrebbero interrompere anche percorsi dove le interruzioni so= no + disabilitate] sono corretti e non interferiscono con il validatore. Ino= ltre, + 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=C3=A0 **enorme** di ver= ifiche +durante l'esecuzione. Il sistema sarebbe diventato praticamente inutilizza= bile +per la sua lentezza se le avessimo fatte davvero per ogni blocco trattenut= o e +per ogni abilitazione delle interruzioni. La complessit=C3=A0 della verifi= ca =C3=A8 +O(N^2), quindi avremmo dovuto fare decine di migliaia di verifiche per ogni +evento, il tutto per poche centinaia di classi. + +Il problema =C3=A8 stato risolto facendo una singola verifica per ogni 'sc= enario di +sincronizzazione' (una sequenza unica di blocchi trattenuti uno dopo l'alt= ro). +Per farlo, viene mantenuta una pila dei blocchi trattenuti, e viene calcol= ato 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= =C3=A0 +essere verificata senza bisogno di blocchi. Se la sequenza dovesse ripeter= si, la +tabella ci dir=C3=A0 che non =C3=A8 necessario verificarla nuovamente. + +Risoluzione dei problemi +------------------------ + +Il massimo numero di classi di blocco che il validatore pu=C3=B2 tracciare= =C3=A8: +MAX_LOCKDEP_KEYS. Oltrepassare questo limite indurr=C3=A0 lokdep a generar= e il +seguente avviso:: + + (DEBUG_LOCKS_WARN_ON(id >=3D MAX_LOCKDEP_KEYS)) + +Di base questo valore =C3=A8 8191, e un classico sistema da ufficio ha men= o di 1000 +classi, dunque questo avviso =C3=A8 solitamente la conseguenza di un probl= ema di +perdita delle classi di blocco o d'inizializzazione dei blocchi. Di seguit= o una +descrizione dei due problemi: + +1. caricare e rimuovere continuamente i moduli mentre il validatore =C3=A8= in + esecuzione porter=C3=A0 ad una perdita di classi di blocco. Il problema= =C3=A8 che ogni + caricamento crea un nuovo insieme di classi di blocco per tutti i blocc= hi di + quel modulo. Tuttavia, la rimozione del modulo non rimuove le vecchie c= lassi + (vedi dopo perch=C3=A9 non le riusiamo). Dunque, il continuo caricament= o e + rimozione di un modulo non fa altro che aumentare il contatore di class= i 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 ogn= uno ha + il proprio spinlock_t consumer=C3=A0 8192 classi di blocco a meno che n= on vengano + esplicitamente inizializzati in esecuzione usando spin_lock_init() inve= ce + 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 bloc= chi li + mapperebbe tutti alla stessa classe di blocco. + + La morale della favola =C3=A8 che dovete sempre inizializzare esplicita= mente i + vostri blocchi. + +Qualcuno potrebbe argomentare che il validatore debba permettere il riuso = di +classi di blocco. Tuttavia, se siete tentati dall'argomento, prima revisio= nate +il codice e pensate alla modifiche necessarie, e tenendo a mente che le cl= assi +di blocco da rimuovere probabilmente sono legate al grafo delle dipendenze= . Pi=C3=B9 +facile a dirsi che a farsi. + +Ovviamente, se non esaurite le classi di blocco, la prossima cosa da fare = =C3=A8 +quella di trovare le classi non funzionanti. Per prima cosa, il seguente c= omando +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 tem= po, +allora c'=C3=A8 probabilmente un problema da qualche parte. Il seguente co= mando pu=C3=B2 +essere utilizzato per identificare le classi di blocchi problematiche:: + + grep "BD" /proc/lockdep + +Eseguite il comando e salvatene l'output, quindi confrontatelo con l'outpu= t di +un'esecuzione successiva per identificare eventuali problemi. Questo stesso +output pu=C3=B2 anche aiutarti a trovare situazioni in cui l'inizializzazi= one del +blocco =C3=A8 stata omessa. + +Lettura ricorsiva dei blocchi +----------------------------- + +Il resto di questo documento vuole dimostrare che certi cicli equivalgono = ad una +possibilit=C3=A0 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 =C3= =A8 +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 ricors= ivo ad +auto infliggersi uno stallo. + +La differenza fra questi due tipi di lettori esiste perch=C3=A9: quelli ri= corsivi +vengono bloccati solo dal trattenimento di un blocco di scrittura, mentre = quelli +non ricorsivi possono essere bloccati dall'attesa di un blocco di scrittur= a. +Consideriamo il seguente esempio:: + + TASK A: TASK B: + + read_lock(X); + write_lock(X); + read_lock_2(X); + +L'attivit=C3=A0 A acquisisce il blocco di lettura X (non importa se di tip= o ricorsivo +o meno) usando read_lock(). Quando l'attivit=C3=A0 B tenter=C3=A0 di acqui= sire il blocco +X, si fermer=C3=A0 e rimarr=C3=A0 in attesa che venga rilasciato. Ora se r= ead_lock_2() =C3=A8 +un tipo lettore ricorsivo, l'attivit=C3=A0 A continuer=C3=A0 perch=C3=A9 g= li scrittori in +attesa non possono bloccare lettori ricorsivi, e non avremo alcuno stallo. +Tuttavia, se read_lock_2() =C3=A8 un lettore non ricorsivo, allora verr=C3= =A0 bloccato +dall'attivit=C3=A0 B e si causer=C3=A0 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 pot= rebbe + bloccare quelli non ricorsivi (perch=C3=A9 potrebbero esistere degli sc= rittori 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 vengo= no +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 ri= mane +in attesta del blocco X, mentre il secondo read_lock() non ha bisogno di +aspettare perch=C3=A9 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'acquisizio= ne (in +particolare il valore del parametro 'read' in lock_acquire()), un blocco p= u=C3=B2 +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 lettu= ra non +ricorsiva, mentre "ricorsivi" i blocchi di lettura ricorsivi. + +I blocchi ricorsivi non si bloccano a vicenda, mentre quelli non ricorsivi= s=C3=AC +(anche in lettura). Un blocco di lettura non ricorsivi pu=C3=B2 bloccare u= no +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=C3=A9 vi sono 3 tipi di bloccatori, allora avremo 9 tip= i 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 tratt= enuto. +In altre parole, vogliamo sapere se esiste un bloccatore L3 che viene bloc= cato +da L1 e un L2 che viene bloccato da L3. Dunque, siamo interessati a (1) qu= ello +che L1 blocca e (2) quello che blocca L2. Di conseguenza, possiamo combina= re +lettori ricorsivi e non per L1 (perch=C3=A9 bloccano gli stessi tipi) e po= ssiamo +combinare scrittori e lettori non ricorsivi per L2 (perch=C3=A9 vengono bl= occati +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 =C3=A8 uno scrittore e Y un lettore r= icorsivo. + +2) -(EN)->: + dipendenza da scrittore esclusivo a bloccatore non ricorsivo. + "X -(EN)->" significa X-> Y, dove X =C3=A8 uno scrittore e Y p= u=C3=B2 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 =C3=A8 un lettore (ricorsivo o meno) = e Y =C3=A8 un + lettore ricorsivo. + +4) -(SN)->: + dipendenza da lettore condiviso a bloccatore non ricorsivo. + "X -(SN)-> Y" significa X -> Y , dove X =C3=A8 un lettore (ric= orsivo + o meno) e Y pu=C3=B2 essere o uno scrittore o un lettore non r= icorsivo. + +Da notare che presi due blocchi, questi potrebbero avere pi=C3=B9 dipenden= za 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 =C3=A8 una serie di nodi e degli archi che li co= ngiungono. +Definiamo un percorso "forte", come il percorso che non ha archi (dipenden= ze) di +tipo -(xR)-> e -(Sx)->. In altre parole, un percorso "forte" =C3=A8 un per= corso da un +blocco ad un altro attraverso le varie dipendenze, e se sul percorso abbia= mo 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=C3=A9 definiamo questo percorso "fort= e". + +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 =C3=A8 sufficiente alla scoperta di uno stal= lo. + +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 parol= e, i +cicli forti sono necessari alla rilevazione degli stallo. + +Con questi due lemmi possiamo facilmente affermare che un percorso chiuso = forte +=C3=A8 sia sufficiente che necessario per avere gli stalli, dunque averli = equivale +alla possibilit=C3=A0 di imbattersi concretamente in uno stallo. Un percor= so chiuso +forte significa che pu=C3=B2 causare stalli, per questo lo definiamo "fort= e", 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=C3=AC che un processo/processore prenda L1 in L1= -> L2, poi +un altro prende L2 in L2 -> L3, e cos=C3=AC 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=C3=A0 acquisire L2 i= n L1 -> L2, +ma prima dovr=C3=A0 attendere che venga rilasciato da chi lo trattiene. Qu= esto perch=C3=A9 +L2 =C3=A8 gi=C3=A0 trattenuto da un altro processo/processore, ed in pi=C3= =B9 L1 -> L2 e L2 -> +L3 non sono -(xR)-> n=C3=A9 -(Sx)-> (la definizione di forte). Questo sign= ifica che L2 +in L1 -> L2 non =C3=A8 un bloccatore non ricorsivo (bloccabile da chiunque= ), e L2 in +L2 -> L3 non =C3=A8 uno scrittore (che blocca chiunque). + +In aggiunta, possiamo trarre una simile conclusione per chi sta trattenend= o L2: +deve aspettare che L3 venga rilasciato, e cos=C3=AC via. Ora possiamo dimo= strare che +chi trattiene Lx deve aspettare che Lx+1 venga rilasciato. Notiamo che Ln+= 1 =C3=A8 +L1, dunque si =C3=A8 creato un ciclo dal quale non possiamo uscire, quindi= si ha uno +stallo. + +Dimostrazione della necessit=C3=A0 (lemma 2): + +Questo lemma equivale a dire che: se siamo in uno scenario di stallo, allo= ra +deve esiste un ciclo forte nel grafo delle dipendenze. + +Secondo Wikipedia[1], se c'=C3=A8 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 ve= nga +rilasciato. Chiamiamo Lx il blocco che attende Px, quindi P1 aspetta L1 e +trattiene Ln. Quindi avremo Ln -> L1 nel grafo delle dipendenze. Similarme= nte, +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=C3=A0 +impossibile che Lx in Px+1 sia un lettore e che Lx in Px sia un lettore +ricorsivo. Questo perch=C3=A9 i lettori (ricorsivi o meno) non bloccano le= ttori +ricorsivi. Dunque, Lx-1 -> Lx e Lx -> Lx+1 non possono essere una coppia di +-(xR)-> -(Sx)->. Questo =C3=A8 vero per ogni ciclo, dunque, questo =C3=A8 = un ciclo forte. + +Riferimenti +----------- + +[1]: https://it.wikipedia.org/wiki/Stallo_(informatica) + +[2]: Shibu, K. (2009). Intro To Embedded Systems (1st ed.). Tata McGraw-Hi= ll diff --git a/Documentation/translations/it_IT/locking/lockstat.rst b/Docume= ntation/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 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Statistiche sui blocchi +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Cosa +=3D=3D=3D=3D + +Come suggerisce il nome, fornisce statistiche sui blocchi. + + +Perch=C3=A9 +=3D=3D=3D=3D=3D=3D + +Perch=C3=A9, tanto per fare un esempio, le contese sui blocchi possono inf= luenzare +significativamente le prestazioni. + +Come +=3D=3D=3D=3D + +*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 + | | + | + | _______/ + |/ + | + __acquired + | + . + + . + | + __release + | + unlock + + lock, unlock - le classiche funzioni di blocco + __* - i punti di collegamento + <> - stati + +Grazie a questi punti di collegamento possiamo fornire le seguenti statist= iche: + +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 process= ore + +acquisitions + - numero di volte che un blocco =C3=A8 stato ottenuto + +hold time + min + - tempo minimo (diverso da zero) che sia mai stato speso trattenendo u= n 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 =C3=A8 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 [] khugepaged_scan_mm_slot+0x57/0x280 + 10 &mm->mmap_sem 96 [] __do_page_fault+0x1d4/0x510 + 11 &mm->mmap_sem 34 [] vm_mmap_pgoff+0x87/0xd0 + 12 &mm->mmap_sem 17 [] vm_munmap+0x41/0x80 + 13 --------------- + 14 &mm->mmap_sem 1 [] dup_mmap+0x2a/0x3f0 + 15 &mm->mmap_sem 60 [] SyS_mprotect+0xe9/0x250 + 16 &mm->mmap_sem 41 [] __do_page_fault+0x1d4/0x510 + 17 &mm->mmap_sem 68 [] 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 [] unix_create1+0x16e/0x1b0 + 24 unix_table_lock 47 [] unix_release_sock+0x31/0x250 + 25 unix_table_lock 15 [] unix_find_other+0x117/0x230 + 26 unix_table_lock 5 [] unix_autobind+0x11f/0x1b0 + 27 --------------- + 28 unix_table_lock 39 [] unix_release_sock+0x31/0x250 + 29 unix_table_lock 49 [] unix_create1+0x16e/0x1b0 + 30 unix_table_lock 20 [] unix_find_other+0x117/0x230 + 31 unix_table_lock 4 [] 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=C3=A0 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). =C3=88 possibile che nelle +statistiche manchi il valore *max con-bounces*. + +Il primo blocco (righe dalla 05 alla 18) =C3=A8 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: *punt= i di +contesa* e *[] simboli*. Il secondo gruppo di punti di contesa sono i = punti +con cui si contende il blocco. + +La parte interna del tempo =C3=A8 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 [] task_rq_lock+0x43/0x75 + 37 &rq->lock 297 [] try_to_wake_up+0x127/0x25a + 38 &rq->lock 360 [] select_task_rq_fair+0x1f0/0x74a + 39 &rq->lock 428 [] scheduler_tick+0x46/0x1fb + 40 --------- + 41 &rq->lock 77 [] task_rq_lock+0x43/0x75 + 42 &rq->lock 174 [] try_to_wake_up+0x127/0x25a + 43 &rq->lock 4715 [] double_rq_lock+0x42/0x54 + 44 &rq->lock 893 [] 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 [] double_rq_lock+0x4f/0x54 + 51 ----------- + 52 &rq->lock/1 5645 [] double_rq_lock+0x42/0x54 + 53 &rq->lock/1 1224 [] schedule+0x157/0x7b8 + 54 &rq->lock/1 4336 [] double_rq_lock+0x4f/0x54 + 55 &rq->lock/1 181 [] 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 blo= cco +annidato di due spinlock. + +Per vedere i blocco pi=C3=B9 contesi:: + + # grep : /proc/lock_stat | head + clockevents_lock: 2926159 2947636 0.15 468= 82.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 6= 06.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 380= 9894 0.15 391.40 3559518.81 0.93 + tasklist_lock-W: 40667 41130 0.23 11= 89.42 428980.51 10.43 270278 510106 = 0.16 653.51 3939674.91 7.72 + tasklist_lock-R: 21298 21305 0.20 13= 10.05 215511.12 10.12 186204 241258 = 0.14 1162.33 1179779.23 4.89 + rcu_node_1: 47656 49022 0.16 6= 35.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 7= 86.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/Doc= umentation/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 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Funzionamento del test *Kernel Lock Torture* +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +CONFIG_LOCK_TORTURE_TEST +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +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=C3=B2 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=C3=A0 di verifica di RCU tramite rcutortur= e. + +Questa verifica consiste nella creazione di un certo numero di thread +del kernel che acquisiscono un blocco e lo trattengono per una certa +quantit=C3=A0 di tempo cos=C3=AC da simulare diversi comportamenti nelle s= ezioni +critiche. La quantit=C3=A0 di contese su un blocco pu=C3=B2 essere simulata +allargando la sezione critica e/o creando pi=C3=B9 thread. + + +Parametri del modulo +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +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 =C3=A8 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 =C3=A8 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=C3=B2 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=3Dy. + + - "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 =C3=A8 zero, il che disabilita + la possibilit=C3=A0 di terminare e spegnere. Questa funzionalit=C3=A0 + pu=C3=B2 essere utile per verifiche automatizzate. + +onoff_interval + Numero di secondi fra ogni tentativo di esecuzione di + un'operazione casuale di CPU-hotplug. Di base =C3=A8 zero, il + che disabilita la funzionalit=C3=A0 di CPU-hotplug. Nei kernel + con CONFIG_HOTPLUG_CPU=3Dn, locktorture si rifiuter=C3=A0, 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 =C3=A8 compilato come parte + integrante del kernel ed eseguito automaticamente all'avvio, + in questo caso =C3=A8 utile perch=C3=A9 permette di non confondere + l'avvio con i processori che vanno e vengono. Questo + parametro =C3=A8 utile sono se CONFIG_HOTPLUG_CPU =C3=A8 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=3D5", quindi si eseguono + verifiche e pause di (circa) cinque secondi. + L'impostazione di "stutter=3D0" fa si che la verifica + venga eseguita continuamente senza fermarsi. + +shuffle_interval + Il numero di secondi per cui un thread debba mantenere + l'affinit=C3=A0 con un sottoinsieme di processori, di base =C3=A8 + 3 secondi. Viene usato assieme a test_no_idle_hz. + +verbose + Abilita le stampe di debug, via printk(). Di base =C3=A8 + abilitato. Queste informazioni aggiuntive sono per la + maggior parte relative ad errori di alto livello e resoconti + da parte dell'struttura 'torture'. + + +Statistiche +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +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=C3=A0 di seguito anc= he una + seconda voce "Reads" + + (C): Numero di volte che il blocco =C3=A8 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 blo= cco. + Questo dovrebbe dare un riscontro positivo -solo- se c'=C3=A8 un ba= co + nell'implementazione delle primitive di sincronizzazione. Altriment= i un + blocco non dovrebbe mai fallire (per esempio, spin_lock()). + Ovviamente lo stesso si applica per (C). Un semplice esempio =C3=A8= il tipo + "lock_busted". + +Uso +=3D=3D=3D + +Il seguente script pu=C3=B2 essere utilizzato per verificare i blocchi:: + + #!/bin/sh + + modprobe locktorture + sleep 3600 + rmmod locktorture + dmesg | grep torture: + +L'output pu=C3=B2 essere manualmente ispezionato cercando il marcatore d'e= rrore +"!!!". Ovviamente potreste voler creare degli script pi=C3=B9 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 probl= emi 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/Docum= entation/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: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Tipologie di blocco e le loro istruzioni +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Introduzione +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Il kernel fornisce un certo numero di primitive di blocco che possiamo div= idere +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 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Blocchi ad attesa con sospensione +--------------------------------- + +I blocchi ad attesa con sospensione possono essere acquisiti solo in un co= ntesti +dov'=C3=A8 possibile la prelazione. + +Diverse implementazioni permettono di usare try_lock() anche in altri cont= esti, +nonostante ci=C3=B2 =C3=A8 bene considerare anche la sicurezza dei corrisp= ondenti +unlock(). Inoltre, vanno prese in considerazione anche le varianti di *deb= ug* +di queste primitive. Insomma, non usate i blocchi ad attesa con sospension= i 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 mecca= nismi, +la disabilitazione della prelazione o delle interruzioni sono puri meccani= smi +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: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + _bh() disabilita / abilita *bottom halves* (interruzioni = software) + _irq() disabilita / abilita le interruzioni + _irqsave/restore() salva e disabilita le interruzioni / ripristina ed a= ttiva le interruzioni + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Semantica del proprietario +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +Eccetto i semafori, i sopracitati tipi di blocchi hanno tutti una semantica +molto stringente riguardo al proprietario di un blocco: + + Il contesto (attivit=C3=A0) 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 +=3D=3D=3D=3D=3D=3D=3D + +I blocchi a mutua esclusione RT (*rtmutex*) sono un sistema a mutua esclus= ione +con supporto all'ereditariet=C3=A0 della priorit=C3=A0 (PI). + +Questo meccanismo ha delle limitazioni sui kernel non-PREEMPT_RT dovuti al= la +prelazione e alle sezioni con interruzioni disabilitate. + +Chiaramente, questo meccanismo non pu=C3=B2 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'=C3=A8 possibile la prelazione, specialmente in co= ntesti +d'interruzione (anche software). Questa conversione permette a spinlock_t e +rwlock_t di essere implementati usando rtmutex. + +semaphore +=3D=3D=3D=3D=3D=3D=3D=3D=3D + +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=C3= =A9 non hanno +un concetto di proprietario, dunque impediscono a PREEMPT_RT d'avere +l'ereditariet=C3=A0 della priorit=C3=A0 sui semafori. Un proprietario scon= osciuto non pu=C3=B2 +ottenere una priorit=C3=A0 superiore. Di consequenza, bloccarsi sui semafo= ri porta +all'inversione di priorit=C3=A0. + + +rw_semaphore +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Il blocco rw_semaphore =C3=A8 un meccanismo che permette pi=C3=B9 lettori = ma un solo scrittore. + +Sui kernel non-PREEMPT_RT l'implementazione =C3=A8 imparziale, quindi prev= iene +l'inedia dei processi scrittori. + +Questi blocchi hanno una semantica molto stringente riguardo il proprietar= io, ma +offre anche interfacce speciali che permettono ai processi non proprietari= di +rilasciare un processo lettore. Queste interfacce funzionano indipendentem= ente +dalla configurazione del kernel. + +rw_semaphore e PREEMPT_RT +------------------------- + +I kernel PREEMPT_RT sostituiscono i rw_semaphore con un'implementazione ba= sata +su rt_mutex, e questo ne modifica l'imparzialit=C3=A0: + + Dato che uno scrittore rw_semaphore non pu=C3=B2 assicurare la propria pr= iorit=C3=A0 ai + suoi lettori, un lettore con priorit=C3=A0 pi=C3=B9 bassa che ha subito l= a prelazione + continuer=C3=A0 a trattenere il blocco, quindi porta all'inedia anche gli= scrittori + con priorit=C3=A0 pi=C3=B9 alta. Per contro, dato che i lettori possono g= arantire la + propria priorit=C3=A0 agli scrittori, uno scrittore a bassa priorit=C3=A0= che subisce la + prelazione vedr=C3=A0 la propria priorit=C3=A0 alzata finch=C3=A9 non ril= ascer=C3=A0 il blocco, e + questo preverr=C3=A0 l'inedia dei processi lettori a causa di uno scritto= re. + + +local_lock +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +I local_lock forniscono nomi agli ambiti di visibilit=C3=A0 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. + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + 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() + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + +Gli ambiti di visibilit=C3=A0 con nome hanno due vantaggi rispetto alle pr= imitive di +base: + + - Il nome del blocco permette di fare un'analisi statica, ed =C3=A8 anch= e chiaro su + cosa si applichi la protezione cosa che invece non si pu=C3=B2 fare co= n le + classiche primitive in quanto sono opache e senza alcun ambito di + visibilit=C3=A0. + + - Se viene abilitato lockdep, allora local_lock ottiene un lockmap che + permette di verificare la bont=C3=A0 della protezione. Per esempio, qu= esto pu=C3=B2 + identificare i casi dove una funzione usa preempt_disable() come mecca= nismo + di protezione in un contesto d'interruzione (anche software). A parte + questo, lockdep_assert_held(&llock) funziona come tutte le altre primi= tive + di sincronizzazione. + +local_lock e PREEMPT_RT +------------------------- + +I kernel PREEMPT_RT sostituiscono local_lock con uno spinlock_t per CPU, q= uindi +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 =C3=A8 il modo pi=C3= =B9 adeguato per +gestire l'accesso concorrente a strutture dati per CPU. + +Questo meccanismo non =C3=A8 adatto alla protezione da prelazione o interr= uzione su +kernel PREEMPT_RT dato che verr=C3=A0 convertito in spinlock_t. + + +raw_spinlock_t e spinlock_t +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +raw_spinlock_t +-------------- + +I blocco raw_spinlock_t =C3=A8 un blocco ad attesa attiva su tutti i tipi = di kernel, +incluso quello PREEMPT_RT. Usate raw_spinlock_t solo in sezioni critiche n= el +cuore del codice, nella gestione delle interruzioni di basso livello, e in= posti +dove =C3=A8 necessario disabilitare la prelazione o le interruzioni. Per e= sempio, per +accedere in modo sicuro lo stato dell'hardware. A volte, i raw_spinlock_t +possono essere usati quando la sezione critica =C3=A8 minuscola, per evita= re 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 ba= sa +sull'uso di rt_mutex. Questo ne modifica il significato: + + - La prelazione non viene disabilitata. + + - I suffissi relativi alla interruzioni (_irq, _irqsave / _irqrestore) pe= r 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 stes= so 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 at= tiva. + +A parte quanto appena discusso, i kernel PREEMPT_RT preservano il signific= ato +di tutti gli altri aspetti di spinlock_t: + + - Le attivit=C3=A0 che trattengono un blocco spinlock_t non migrano su al= tri + processori. Disabilitando la prelazione, i kernel non-PREEMPT_RT evitan= o 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=C3=A0 subisce la prelazione. + + - Lo stato di un'attivit=C3=A0 si mantiene durante le acquisizioni del bl= occo al + fine di garantire che le regole basate sullo stato delle attivit=C3=A0 = si possano + applicare a tutte le configurazioni del kernel. I kernel non-PREEMPT_RT + lasciano lo stato immutato. Tuttavia, la funzionalit=C3=A0 PREEMPT_RT d= eve + cambiare lo stato se l'attivit=C3=A0 si blocca durante l'acquisizione. = Dunque, + salva lo stato attuale prima di bloccarsi ed il rispettivo risveglio lo + ripristiner=C3=A0 come nell'esempio seguente:: + + task->state =3D TASK_INTERRUPTIBLE + lock() + block() + task->saved_state =3D task->state + task->state =3D TASK_UNINTERRUPTIBLE + schedule() + lock wakeup + task->state =3D task->saved_state + + Altri tipi di risvegli avrebbero impostato direttamente lo stato a RUNN= ING, + ma in questo caso non avrebbe funzionato perch=C3=A9 l'attivit=C3=A0 de= ve rimanere + bloccata fintanto che il blocco viene trattenuto. Quindi, lo stato salv= ato + viene messo a RUNNING quando il risveglio di un non-blocco cerca di + risvegliare un'attivit=C3=A0 bloccata in attesa del rilascio di uno spi= nlock. Poi, + quando viene completata l'acquisizione del blocco, il suo risveglio + ripristiner=C3=A0 lo stato salvato, in questo caso a RUNNING:: + + task->state =3D TASK_INTERRUPTIBLE + lock() + block() + task->saved_state =3D task->state + task->state =3D TASK_UNINTERRUPTIBLE + schedule() + non lock wakeup + task->saved_state =3D TASK_RUNNING + + lock wakeup + task->state =3D task->saved_state + + Questo garantisce che il vero risveglio non venga perso. + +rwlock_t +=3D=3D=3D=3D=3D=3D=3D=3D + +Il blocco rwlock_t =C3=A8 un meccanismo che permette pi=C3=B9 lettori ma u= n solo scrittore. + +Sui kernel non-PREEMPT_RT questo =C3=A8 un blocco ad attesa e per i suoi s= uffissi si +applicano le stesse regole per spinlock_t. La sua implementazione =C3=A8 i= mparziale, +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=C3=B2 assicurare la propria = priorit=C3=A0 ai + suoi lettori, un lettore con priorit=C3=A0 pi=C3=B9 bassa che ha subito= la prelazione + continuer=C3=A0 a trattenere il blocco, quindi porta all'inedia anche g= li + scrittori con priorit=C3=A0 pi=C3=B9 alta. Per contro, dato che i letto= ri possono + garantire la propria priorit=C3=A0 agli scrittori, uno scrittore a bass= a priorit=C3=A0 + che subisce la prelazione vedr=C3=A0 la propria priorit=C3=A0 alzata fi= nch=C3=A9 non + rilascer=C3=A0 il blocco, e questo preverr=C3=A0 l'inedia dei processi = lettori a causa + di uno scrittore. + + +Precisazioni su PREEMPT_RT +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +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=C3=A0 come ci si aspetta:: + + local_lock_irq(&local_lock); + raw_spin_lock(&lock); + +ed =C3=A8 equivalente a:: + + raw_spin_lock_irq(&lock); + +Ma su un kernel PREEMPT_RT questo codice non funzioner=C3=A0 perch=C3=A9 l= ocal_lock_irq() +si traduce in uno spinlock_t per CPU che non disabilita n=C3=A9 le interru= zioni n=C3=A9 la +prelazione. Il seguente codice funzioner=C3=A0 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 =C3=A8 che ognuno di l= oro ha un +ambito di protezione ben preciso. Dunque, la seguente sostituzione =C3=A8 = errate:: + + + func1() + { + local_irq_save(flags); -> local_lock_irqsave(&local_lock_1, flags); + func3(); + local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_1, fl= ags); + } + + func2() + { + local_irq_save(flags); -> local_lock_irqsave(&local_lock_2, flags); + func3(); + local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_2, fl= ags); + } + + 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 seriali= zzare +i chiamanti di func3(). L'*assert* di lockdep verr=C3=A0 attivato su un ke= rnel +PREEMPT_RT perch=C3=A9 local_lock_irqsave() non disabilita le interruzione= a casa +della specifica semantica di spinlock_t in PREEMPT_RT. La corretta sostitu= zione +=C3=A8:: + + func1() + { + local_irq_save(flags); -> local_lock_irqsave(&local_lock, flags); + func3(); + local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flag= s); + } + + func2() + { + local_irq_save(flags); -> local_lock_irqsave(&local_lock, flags); + func3(); + local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flag= s); + } + + 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 =C3=A8 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=C3=A0 perch=C3=A9 gli rt= mutex richiedono +un contesto con la possibilit=C3=A0 di prelazione. Al suo posto, usate +spin_lock_irq() o spin_lock_irqsave() e le loro controparti per il rilasci= o. I +kernel PREEMPT_RT offrono un meccanismo local_lock per i casi in cui la +disabilitazione delle interruzioni ed acquisizione di un blocco devono rim= anere +separati. Acquisire un local_lock =C3=A0ncora un processo ad una CPU perme= ttendo cose +come un'acquisizione di un blocco con interruzioni disabilitate per singol= a CPU. + +Il tipico scenario =C3=A8 quando si vuole proteggere una variabile di proc= essore nel +contesto di un thread:: + + + struct foo *p =3D get_cpu_ptr(&var1); + + spin_lock(&p->lock); + p->count +=3D this_cpu_read(var2); + +Questo codice =C3=A8 corretto su un kernel non-PREEMPT_RT, ma non lo =C3= =A8 su un +PREEMPT_RT. La modifica della semantica di spinlock_t su PREEMPT_RT non pe= rmette +di acquisire p->lock perch=C3=A9, implicitamente, get_cpu_ptr() disabilita= la +prelazione. La seguente sostituzione funzioner=C3=A0 su entrambe i kernel:: + + struct foo *p; + + migrate_disable(); + p =3D this_cpu_ptr(&var1); + spin_lock(&p->lock); + p->count +=3D 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 variabi= li var1 e +var2 rimangano sulla stessa CPU fintanto che il processo rimane prelabile. + +La sostituzione con migrate_disable() non funzioner=C3=A0 nel seguente sce= nario:: + + func() + { + struct foo *p; + + migrate_disable(); + p =3D this_cpu_ptr(&var1); + p->val =3D func2(); + +Questo non funziona perch=C3=A9 migrate_disable() non protegge dal ritorno= da un +processo che aveva avuto il diritto di prelazione. Una sostituzione pi=C3= =B9 adatta +per questo caso =C3=A8:: + + func() + { + struct foo *p; + + local_lock(&foo_lock); + p =3D this_cpu_ptr(&var1); + p->val =3D func2(); + +Su un kernel non-PREEMPT_RT, questo codice protegge dal rientro disabilita= ndo la +prelazione. Su un kernel PREEMPT_RT si ottiene lo stesso risultato acquise= ndo 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 spin= lock_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 perfettam= ente:: + + raw_spin_lock(&lock); + p =3D kmalloc(sizeof(*p), GFP_ATOMIC); + +Ma lo stesso codice non funziona su un kernel PREEMPT_RT perch=C3=A9 l'all= ocatore di +memoria pu=C3=B2 essere oggetto di prelazione e quindi non pu=C3=B2 essere= chiamato in un +contesto atomico. Tuttavia, si pu=C3=B2 chiamare l'allocatore di memoria q= uando si +trattiene un blocco *non-raw* perch=C3=A9 non disabilitano la prelazione s= ui kernel +PREEMPT_RT:: + + spin_lock(&lock); + p =3D kmalloc(sizeof(*p), GFP_ATOMIC); + + +bit spinlocks +------------- + +I kernel PREEMPT_RT non possono sostituire i bit spinlock perch=C3=A9 un s= ingolo bit +=C3=A8 troppo piccolo per farci stare un rtmutex. Dunque, la semantica dei= bit +spinlock =C3=A8 mantenuta anche sui kernel PREEMPT_RT. Quindi, le precisaz= ioni 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, ques= to 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 trasparent= e. + + +Regole d'annidamento dei tipi di blocchi +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Le regole principali sono: + + - I tipi di blocco appartenenti alla stessa categoria possono essere ann= idati + liberamente a patto che si rispetti l'ordine di blocco al fine di evit= are + stalli. + + - I blocchi con sospensione non possono essere annidati in blocchi del t= ipo + 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_R= T. + +Il fatto che un kernel PREEMPT_RT cambi i blocchi spinlock_t e rwlock_t da= l tipo +ad attesa attiva a quello con sospensione, e che sostituisca local_lock co= n uno +spinlock_t per CPU, significa che non possono essere acquisiti quando si = =C3=A8 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=C3=A0 e q= uesto sia +con o senza PREEMPT_RT. --=20 2.39.2