Commit fdf0345e authored by Federico Vaga's avatar Federico Vaga Committed by Jonathan Corbet

doc:it: add some process/* translations

Translated documents:
- 2.Process
- 3.Early-stage
- 4.Coding
- 5.Posting
- 6.Followthrough
- 7.AdvancedTopics
- 8.Conclusion
- adding-syscalls
Signed-off-by: default avatarFederico Vaga <federico.vaga@vaga.pv.it>
Signed-off-by: default avatarAlessia Mantegazza <amantegazza@vaga.pv.it>
Signed-off-by: default avatarJonathan Corbet <corbet@lwn.net>
parent a4a2bf0e
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/2.Process.rst <development_process>`
:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>
.. _it_development_process:
Come funziona il processo di sviluppo
=====================================
.. warning::
Lo sviluppo del Kernel agli inizi degli anno '90 era abbastanza libero, con
un numero di utenti e sviluppatori relativamente basso. Con una base
di milioni di utenti e con 2000 sviluppatori coinvolti nel giro di un anno,
il kernel da allora ha messo in atto un certo numero di procedure per rendere
lo sviluppo più agevole. È richiesta una solida conoscenza di come tale
processo si svolge per poter esserne parte attiva.
TODO ancora da tradurre
Il quadro d'insieme
-------------------
Gli sviluppatori kernel utilizzano un calendario di rilascio generico, dove
ogni due o tre mesi viene effettuata un rilascio importante del kernel.
I rilasci più recenti sono stati:
====== =================
4.11 Aprile 30, 2017
4.12 Luglio 2, 2017
4.13 Settembre 3, 2017
4.14 Novembre 12, 2017
4.15 Gennaio 28, 2018
4.16 Aprile 1, 2018
====== =================
Ciascun rilascio 4.x è un importante rilascio del kernel con nuove
funzionalità, modifiche interne dell'API, e molto altro. Un tipico
rilascio 4.x contiene quasi 13,000 gruppi di modifiche con ulteriori
modifiche a parecchie migliaia di linee di codice. La 4.x. è pertanto la
linea di confine nello sviluppo del kernel Linux; il kernel utilizza un sistema
di sviluppo continuo che integra costantemente nuove importanti modifiche.
Viene seguita una disciplina abbastanza lineare per l'inclusione delle
patch di ogni rilascio. All'inizio di ogni ciclo di sviluppo, la
"finestra di inclusione" viene dichiarata aperta. In quel momento il codice
ritenuto sufficientemente stabile(e che è accettato dalla comunità di sviluppo)
viene incluso nel ramo principale del kernel. La maggior parte delle
patch per un nuovo ciclo di sviluppo (e tutte le più importanti modifiche)
saranno inserite durante questo periodo, ad un ritmo che si attesta sulle
1000 modifiche ("patch" o "gruppo di modifiche") al giorno.
(per inciso, vale la pena notare che i cambiamenti integrati durante la
"finestra di inclusione" non escono dal nulla; questi infatti, sono stati
raccolti e, verificati in anticipo. Il funzionamento di tale procedimento
verrà descritto dettagliatamente più avanti).
La finestra di inclusione resta attiva approssimativamente per due settimane.
Al termine di questo periodo, Linus Torvald dichiarerà che la finestra è
chiusa e rilascerà il primo degli "rc" del kernel.
Per il kernel che è destinato ad essere 2.6.40, per esempio, il rilascio
che emerge al termine della finestra d'inclusione si chiamerà 2.6.40-rc1.
Questo rilascio indica che il momento di aggiungere nuovi componenti è
passato, e che è iniziato il periodo di stabilizzazione del prossimo kernel.
Nelle successive sei/dieci settimane, potranno essere sottoposte solo modifiche
che vanno a risolvere delle problematiche. Occasionalmente potrà essere
consentita una modifica più consistente, ma tali occasioni sono rare.
Gli sviluppatori che tenteranno di aggiungere nuovi elementi al di fuori della
finestra di inclusione, tendenzialmente, riceveranno un accoglienza poco
amichevole. Come regola generale: se vi perdete la finestra di inclusione per
un dato componente, la cosa migliore da fare è aspettare il ciclo di sviluppo
successivo (un'eccezione può essere fatta per i driver per hardware non
supportati in precedenza; se toccano codice non facente parte di quello
attuale, che non causino regressioni e che potrebbero essere aggiunti in
sicurezza in un qualsiasi momento)
Mentre le correzioni si aprono la loro strada all'interno del ramo principale,
il ritmo delle modifiche rallenta col tempo. Linus rilascia un nuovo
kernel -rc circa una volta alla settimana; e ne usciranno circa 6 o 9 prima
che il kernel venga considerato sufficientemente stabile e che il rilascio
finale 2.6.x venga fatto. A quel punto tutto il processo ricomincerà.
Esempio: ecco com'è andato il ciclo di sviluppo della versione 4.16
(tutte le date si collocano nel 2018)
============== =======================================
Gennaio 28 4.15 rilascio stabile
Febbraio 11 4.16-rc1, finestra di inclusione chiusa
Febbraio 18 4.16-rc2
Febbraio 25 4.16-rc3
Marzo 4 4.16-rc4
Marzo 11 4.16-rc5
Marzo 18 4.16-rc6
Marzo 25 4.16-rc7
Aprile 1 4.17 rilascio stabile
============== =======================================
In che modo gli sviluppatori decidono quando chiudere il ciclo di sviluppo e
creare quindi una rilascio stabile? Un metro valido è il numero di regressioni
rilevate nel precedente rilascio. Nessun baco è il benvenuto, ma quelli che
procurano problemi su sistemi che hanno funzionato in passato sono considerati
particolarmente seri. Per questa ragione, le modifiche che portano ad una
regressione sono viste sfavorevolmente e verranno quasi sicuramente annullate
durante il periodo di stabilizzazione.
L'obiettivo degli sviluppatori è quello di aggiustare tutte le regressioni
conosciute prima che avvenga il rilascio stabile. Nel mondo reale, questo
tipo di perfezione difficilmente viene raggiunta; esistono troppe variabili
in un progetto di questa portata. Arriva un punto dove ritardare il rilascio
finale peggiora la situazione; la quantità di modifiche in attesa della
prossima finestra di inclusione crescerà enormemente, creando ancor più
regressioni al giro successivo. Quindi molti kernel 4.x escono con una
manciata di regressioni delle quali, si spera, nessuna è grave.
Una volta che un rilascio stabile è fatto, il suo costante mantenimento è
affidato al "squadra stabilità", attualmente composta da Greg Kroah-Hartman.
Questa squadra rilascia occasionalmente degli aggiornamenti relativi al
rilascio stabile usando la numerazione 4.x.y. Per essere presa in
considerazione per un rilascio d'aggiornamento, una modifica deve:
(1) correggere un baco importante (2) essere già inserita nel ramo principale
per il prossimo sviluppo del kernel. Solitamente, passato il loro rilascio
iniziale, i kernel ricevono aggiornamenti per più di un ciclo di sviluppo.
Quindi, per esempio, la storia del kernel 4.13 appare così:
============== ===============================
Settembre 3 4.13 rilascio stabile
Settembre 13 4.13.1
Settembre 20 4.13.2
Settembre 27 4.13.3
Ottobre 5 4.13.4
Ottobre 12 4.13.5
... ...
Novembre 24 4.13.16
============== ===============================
La 4.13.16 fu l'aggiornamento finale per la versione 4.13.
Alcuni kernel sono destinati ad essere kernel a "lungo termine"; questi
riceveranno assistenza per un lungo periodo di tempo. Al momento in cui
scriviamo, i manutentori dei kernel stabili a lungo termine sono:
====== ====================== ==========================================
3.16 Ben Hutchings (kernel stabile molto più a lungo termine)
4.1 Sasha Levin
4.4 Greg Kroah-Hartman (kernel stabile molto più a lungo termine)
4.9 Greg Kroah-Hartman
4.14 Greg Kroah-Hartman
====== ====================== ==========================================
Questa selezione di kernel di lungo periodo sono puramente dovuti ai loro
manutentori, alla loro necessità e al tempo per tenere aggiornate proprio
quelle versioni. Non ci sono altri kernel a lungo termine in programma per
alcun rilascio in arrivo.
Il ciclo di vita di una patch
-----------------------------
Le patch non passano direttamente dalla tastiera dello sviluppatori
al ramo principale del kernel. Esiste, invece, una procedura disegnata
per assicurare che ogni patch sia di buona qualità e desiderata nel
ramo principale. Questo processo avviene velocemente per le correzioni
meno importanti, o, nel caso di patch ampie e controverse, va avanti per anni.
Per uno sviluppatore la maggior frustrazione viene dalla mancanza di
comprensione di questo processo o dai tentativi di aggirarlo.
Nella speranza di ridurre questa frustrazione, questo documento spiegherà
come una patch viene inserita nel kernel. Ciò che segue è un'introduzione
che descrive il processo ideale. Approfondimenti verranno invece trattati
più avanti.
Una patch attraversa, generalmente, le seguenti fasi:
- Progetto. In questa fase sono stabilite quelli che sono i requisiti
della modifica - e come verranno soddisfatti. Il lavoro di progettazione
viene spesso svolto senza coinvolgere la comunità, ma è meglio renderlo
il più aperto possibile; questo può far risparmiare molto tempo evitando
eventuali riprogettazioni successive.
- Prima revisione. Le patch vengono pubblicate sulle liste di discussione
interessate, e gli sviluppatori in quella lista risponderanno coi loro
commenti. Se si svolge correttamente, questo procedimento potrebbe far
emergere problemi rilevanti in una patch.
- Revisione più ampia. Quando la patch è quasi pronta per essere inserita
nel ramo principale, un manutentore importante del sottosistema dovrebbe
accettarla - anche se, questa accettazione non è una garanzia che la
patch arriverà nel ramo principale. La patch sarà visibile nei sorgenti
del sottosistema in questione e nei sorgenti -next (descritti sotto).
Quando il processo va a buon fine, questo passo porta ad una revisione
più estesa della patch e alla scoperta di problemi d'integrazione
con il lavoro altrui.
- Per favore, tenete da conto che la maggior parte dei manutentori ha
anche un lavoro quotidiano, quindi integrare le vostre patch potrebbe
non essere la loro priorità più alta. Se una vostra patch riceve
dei suggerimenti su dei cambiamenti necessari, dovreste applicare
quei cambiamenti o giustificare perché non sono necessari. Se la vostra
patch non riceve alcuna critica ma non è stata integrata dal
manutentore del driver o sottosistema, allora dovreste continuare con
i necessari aggiornamenti per mantenere la patch aggiornata al kernel
più recente cosicché questa possa integrarsi senza problemi; continuate
ad inviare gli aggiornamenti per essere revisionati e integrati.
- Inclusione nel ramo principale. Eventualmente, una buona patch verrà
inserita all'interno nel repositorio principale, gestito da
Linus Torvalds. In questa fase potrebbero emergere nuovi problemi e/o
commenti; è importante che lo sviluppatore sia collaborativo e che sistemi
ogni questione che possa emergere.
- Rilascio stabile. Ora, il numero di utilizzatori che sono potenzialmente
toccati dalla patch è aumentato, quindi, ancora una volta, potrebbero
emergere nuovi problemi.
- Manutenzione di lungo periodo. Nonostante sia possibile che uno sviluppatore
si dimentichi del codice dopo la sua integrazione, questo comportamento
lascia una brutta impressione nella comunità di sviluppo. Integrare il
codice elimina alcuni degli oneri facenti parte della manutenzione, in
particolare, sistemerà le problematiche causate dalle modifiche all'API.
Ma lo sviluppatore originario dovrebbe continuare ad assumersi la
responsabilità per il codice se quest'ultimo continua ad essere utile
nel lungo periodo.
Uno dei più grandi errori fatti dagli sviluppatori kernel (o dai loro datori
di lavoro) è quello di cercare di ridurre tutta la procedura ad una singola
"integrazione nel remo principale". Questo approccio inevitabilmente conduce
a una condizione di frustrazione per tutti coloro che sono coinvolti.
Come le modifiche finiscono nel Kernel
--------------------------------------
Esiste una sola persona che può inserire le patch nel repositorio principale
del kernel: Linus Torvalds. Ma, di tutte le 9500 patch che entrarono nella
versione 2.6.38 del kernel, solo 112 (circa l'1,3%) furono scelte direttamente
da Linus in persona. Il progetto del kernel è cresciuto fino a raggiungere
una dimensione tale per cui un singolo sviluppatore non può controllare e
selezionare indipendentemente ogni modifica senza essere supportato.
La via scelta dagli sviluppatori per indirizzare tale crescita è stata quella
di utilizzare un sistema di "sottotenenti" basato sulla fiducia.
Il codice base del kernel è spezzato in una serie si sottosistemi: rete,
supporto per specifiche architetture, gestione della memoria, video e
strumenti, etc. Molti sottosistemi hanno un manutentore designato: ovvero uno
sviluppatore che ha piena responsabilità di tutto il codice presente in quel
sottosistema. Tali manutentori di sottosistema sono i guardiani
(in un certo senso) della parte di kernel che gestiscono; sono coloro che
(solitamente) accetteranno una patch per l'inclusione nel ramo principale
del kernel.
I manutentori di sottosistema gestiscono ciascuno la propria parte dei sorgenti
del kernel, utilizzando abitualmente (ma certamente non sempre) git.
Strumenti come git (e affini come quilt o mercurial) permettono ai manutentori
di stilare una lista delle patch, includendo informazioni sull'autore ed
altri metadati. In ogni momento, il manutentore può individuare quale patch
nel sua repositorio non si trova nel ramo principale.
Quando la "finestra di integrazione" si apre, i manutentori di alto livello
chiederanno a Linus di "prendere" dai loro repositori le modifiche che hanno
selezionato per l'inclusione. Se Linus acconsente, il flusso di patch si
convoglierà nel repositorio di quest ultimo, divenendo così parte del ramo
principale del kernel. La quantità d'attenzione che Linus presta alle
singole patch ricevute durante l'operazione di integrazione varia.
È chiaro che, qualche volta, guardi più attentamente. Ma, come regola
generale, Linus confida nel fatto che i manutentori di sottosistema non
selezionino pessime patch.
I manutentori di sottosistemi, a turno, possono "prendere" patch
provenienti da altri manutentori. Per esempio, i sorgenti per la rete rete
sono costruiti da modifiche che si sono accumulate inizialmente nei sorgenti
dedicati ai driver per dispositivi di rete, rete senza fili, ecc. Tale
catena di repositori può essere più o meno lunga, benché raramente ecceda
i due o tre collegamenti. Questo processo è conosciuto come
"la catena della fiducia", perché ogni manutentore all'interno della
catena si fida di coloro che gestiscono i livelli più bassi.
Chiaramente, in un sistema come questo, l'inserimento delle patch all'interno
del kernel si basa sul trovare il manutentore giusto. Di norma, inviare
patch direttamente a Linus non è la via giusta.
Sorgenti -next
--------------
La catena di sottosistemi guida il flusso di patch all'interno del kernel,
ma solleva anche un interessante quesito: se qualcuno volesse vedere tutte le
patch pronte per la prossima finestra di integrazione?
Gli sviluppatori si interesseranno alle patch in sospeso per verificare
che non ci siano altri conflitti di cui preoccuparsi; una modifica che, per
esempio, cambia il prototipo di una funzione fondamentale del kernel andrà in
conflitto con qualsiasi altra modifica che utilizzi la vecchia versione di
quella funzione. Revisori e tester vogliono invece avere accesso alle
modifiche nella loro totalità prima che approdino nel ramo principale del
kernel. Uno potrebbe prendere le patch provenienti da tutti i sottosistemi
d'interesse, ma questo sarebbe un lavoro enorme e fallace.
La risposta ci viene sotto forma di sorgenti -next, dove i sottosistemi sono
raccolti per essere testati e controllati. Il più vecchio di questi sorgenti,
gestito da Andrew Morton, è chiamato "-mm" (memory management, che è l'inizio
di tutto). L'-mm integra patch proveniente da una lunga lista di sottosistemi;
e ha, inoltre, alcune patch destinate al supporto del debugging.
Oltre a questo, -mm contiene una raccolta significativa di patch che sono
state selezionate da Andrew direttamente. Queste patch potrebbero essere
state inviate in una lista di discussione, o possono essere applicate ad una
parte del kernel per la quale non esiste un sottosistema dedicato.
Di conseguenza, -mm opera come una specie di sottosistema "ultima spiaggia";
se per una patch non esiste una via chiara per entrare nel ramo principale,
allora è probabile che finirà in -mm. Le patch passate per -mm
eventualmente finiranno nel sottosistema più appropriato o saranno inviate
direttamente a Linus. In un tipico ciclo di sviluppo, circa il 5-10% delle
patch andrà nel ramo principale attraverso -mm.
La patch -mm correnti sono disponibili nella cartella "mmotm" (-mm of
the moment) all'indirizzo:
http://www.ozlabs.org/~akpm/mmotm/
È molto probabile che l'uso dei sorgenti MMOTM diventi un'esperienza
frustrante; ci sono buone probabilità che non compili nemmeno.
I sorgenti principali per il prossimo ciclo d'integrazione delle patch
è linux-next, gestito da Stephen Rothwell. I sorgenti linux-next sono, per
definizione, un'istantanea di come dovrà apparire il ramo principale dopo che
la prossima finestra di inclusione si chiuderà. I linux-next sono annunciati
sulla lista di discussione linux-kernel e linux-next nel momento in cui
vengono assemblati; e possono essere scaricate da:
http://www.kernel.org/pub/linux/kernel/next/
Linux-next è divenuto parte integrante del processo di sviluppo del kernel;
tutte le patch incorporate durante una finestra di integrazione dovrebbero
aver trovato la propria strada in linux-next, a volte anche prima dell'apertura
della finestra di integrazione.
Sorgenti in preparazione
------------------------
Nei sorgenti del kernel esiste la cartella drivers/staging/, dove risiedono
molte sotto-cartelle per i driver o i filesystem che stanno per essere aggiunti
al kernel. Questi restano nella cartella drivers/staging fintanto che avranno
bisogno di maggior lavoro; una volta completato, possono essere spostate
all'interno del kernel nel posto più appropriato. Questo è il modo di tener
traccia dei driver che non sono ancora in linea con gli standard di codifica
o qualità, ma che le persone potrebbero voler usare ugualmente e tracciarne
lo sviluppo.
Greg Kroah-Hartman attualmente gestisce i sorgenti in preparazione. I driver
che non sono completamente pronti vengono inviati a lui, e ciascun driver avrà
la propria sotto-cartella in drivers/staging/. Assieme ai file sorgenti
dei driver, dovrebbe essere presente nella stessa cartella anche un file TODO.
Il file TODO elenca il lavoro ancora da fare su questi driver per poter essere
accettati nel kernel, e indica anche la lista di persone da inserire in copia
conoscenza per ogni modifica fatta. Le regole attuali richiedono che i
driver debbano, come minimo, compilare adeguatamente.
La *preparazione* può essere una via relativamente facile per inserire nuovi
driver all'interno del ramo principale, dove, con un po' di fortuna, saranno
notati da altri sviluppatori e migliorati velocemente. Entrare nella fase
di preparazione non è però la fine della storia, infatti, il codice che si
trova nella cartella staging che non mostra regolari progressi potrebbe
essere rimosso. Le distribuzioni, inoltre, tendono a dimostrarsi relativamente
riluttanti nell'attivare driver in preparazione. Quindi lo preparazione è,
nel migliore dei casi, una tappa sulla strada verso il divenire un driver
del ramo principale.
Strumenti
---------
Come è possibile notare dal testo sopra, il processo di sviluppo del kernel
dipende pesantemente dalla capacità di guidare la raccolta di patch in
diverse direzioni. L'intera cosa non funzionerebbe se non venisse svolta
con l'uso di strumenti appropriati e potenti. Spiegare l'uso di tali
strumenti non è lo scopo di questo documento, ma c'è spazio per alcuni
consigli.
In assoluto, nella comunità del kernel, predomina l'uso di git come sistema
di gestione dei sorgenti. Git è una delle diverse tipologie di sistemi
distribuiti di controllo versione che sono stati sviluppati nella comunità
del software libero. Esso è calibrato per lo sviluppo del kernel, e si
comporta abbastanza bene quando ha a che fare con repositori grandi e con un
vasto numero di patch. Git ha inoltre la reputazione di essere difficile
da imparare e utilizzare, benché stia migliorando. Agli sviluppatori
del kernel viene richiesta un po' di familiarità con git; anche se non lo
utilizzano per il proprio lavoro, hanno bisogno di git per tenersi al passo
con il lavoro degli altri sviluppatori (e con il ramo principale).
Git è ora compreso in quasi tutte le distribuzioni Linux. Esiste una sito che
potete consultare:
http://git-scm.com/
Qui troverete i riferimenti alla documentazione e alle guide passo-passo.
Tra gli sviluppatori Kernel che non usano git, la scelta alternativa più
popolare è quasi sicuramente Mercurial:
http://www.selenic.com/mercurial/
Mercurial condivide diverse caratteristiche con git, ma fornisce
un'interfaccia che potrebbe risultare più semplice da utilizzare.
L'altro strumento che vale la pena conoscere è Quilt:
http://savannah.nongnu.org/projects/quilt/
Quilt è un sistema di gestione delle patch, piuttosto che un sistema
di gestione dei sorgenti. Non mantiene uno storico degli eventi; ma piuttosto
è orientato verso il tracciamento di uno specifico insieme di modifiche
rispetto ad un codice in evoluzione. Molti dei più grandi manutentori di
sottosistema utilizzano quilt per gestire le patch che dovrebbero essere
integrate. Per la gestione di certe tipologie di sorgenti (-mm, per esempio),
quilt è il miglior strumento per svolgere il lavoro.
Liste di discussione
--------------------
Una grossa parte del lavoro di sviluppo del Kernel Linux viene svolto tramite
le liste di discussione. È difficile essere un membro della comunità
pienamente coinvolto se non si partecipa almeno ad una lista da qualche
parte. Ma, le liste di discussione di Linux rappresentano un potenziale
problema per gli sviluppatori, che rischiano di venir sepolti da un mare di
email, restare incagliati nelle convenzioni in vigore nelle liste Linux,
o entrambi.
Molte delle liste di discussione del Kernel girano su vger.kernel.org;
l'elenco principale lo si trova sul sito:
http://vger.kernel.org/vger-lists.html
Esistono liste gestite altrove; un certo numero di queste sono in
lists.redhat.com.
La lista di discussione principale per lo sviluppo del kernel è, ovviamente,
linux-kernel. Questa lista è un luogo ostile dove trovarsi; i volumi possono
raggiungere i 500 messaggi al giorno, la quantità di "rumore" è elevata,
la conversazione può essere strettamente tecnica e i partecipanti non sono
sempre preoccupati di mostrare un alto livello di educazione. Ma non esiste
altro luogo dove la comunità di sviluppo del kernel si unisce per intero;
gli sviluppatori che evitano tale lista si perderanno informazioni importanti.
Ci sono alcuni consigli che possono essere utili per sopravvivere a
linux-kernel:
- Tenete la lista in una cartella separata, piuttosto che inserirla nella
casella di posta principale. Così da essere in grado di ignorare il flusso
di mail per un certo periodo di tempo.
- Non cercate di seguire ogni conversazione - nessuno lo fa. È importante
filtrare solo gli argomenti d'interesse (sebbene va notato che le
conversazioni di lungo periodo possono deviare dall'argomento originario
senza cambiare il titolo della mail) e le persone che stanno partecipando.
- Non alimentate i troll. Se qualcuno cerca di creare nervosismo, ignoratelo.
- Quando rispondete ad una mail linux-kernel (o ad altre liste) mantenete
tutti i Cc:. In assenza di importanti motivazioni (come una richiesta
esplicita), non dovreste mai togliere destinatari. Assicuratevi sempre che
la persona alla quale state rispondendo sia presente nella lista Cc. Questa
usanza fa si che divenga inutile chiedere esplicitamente di essere inseriti
in copia nel rispondere al vostro messaggio.
- Cercate nell'archivio della lista (e nella rete nella sua totalità) prima
di far domande. Molti sviluppatori possono divenire impazienti con le
persone che chiaramente non hanno svolto i propri compiti a casa.
- Evitate il *top-posting* (cioè la pratica di mettere la vostra risposta sopra
alla frase alla quale state rispondendo). Ciò renderebbe la vostra risposta
difficile da leggere e genera scarsa impressione.
- Chiedete nella lista di discussione corretta. Linux-kernel può essere un
punto di incontro generale, ma non è il miglior posto dove trovare
sviluppatori da tutti i sottosistemi.
Infine, la ricerca della corretta lista di discussione è uno degli errori più
comuni per gli sviluppatori principianti. Qualcuno che pone una domanda
relativa alla rete su linux-kernel riceverà quasi certamente il suggerimento
di chiedere sulla lista netdev, che è la lista frequentata dagli sviluppatori
di rete. Ci sono poi altre liste per i sottosistemi SCSI, video4linux, IDE,
filesystem, etc. Il miglior posto dove cercare una lista di discussione è il
file MAINTAINERS che si trova nei sorgenti del kernel.
Iniziare con lo sviluppo del Kernel
-----------------------------------
Sono comuni le domande sul come iniziare con lo sviluppo del kernel - sia da
singole persone che da aziende. Altrettanto comuni sono i passi falsi che
rendono l'inizio di tale relazione più difficile di quello che dovrebbe essere.
Le aziende spesso cercano di assumere sviluppatori noti per creare un gruppo
di sviluppo iniziale. Questo, in effetti, può essere una tecnica efficace.
Ma risulta anche essere dispendiosa e non va ad accrescere il bacino di
sviluppatori kernel con esperienza. È possibile anche "portare a casa"
sviluppatori per accelerare lo sviluppo del kernel, dando comunque
all'investimento un po' di tempo. Prendersi questo tempo può fornire
al datore di lavoro un gruppo di sviluppatori che comprendono sia il kernel
che l'azienda stessa, e che possono supportare la formazione di altre persone.
Nel medio periodo, questa è spesso uno delle soluzioni più proficue.
I singoli sviluppatori sono spesso, comprensibilmente, una perdita come punto
di partenza. Iniziare con un grande progetto può rivelarsi intimidatorio;
spesso all'inizio si vuole solo verificare il terreno con qualcosa di piccolo.
Questa è una delle motivazioni per le quali molti sviluppatori saltano alla
creazione di patch che vanno a sistemare errori di battitura o
problematiche minori legate allo stile del codice. Sfortunatamente, tali
patch creano un certo livello di rumore che distrae l'intera comunità di
sviluppo, quindi, sempre di più, esse vengono degradate. I nuovi sviluppatori
che desiderano presentarsi alla comunità non riceveranno l'accoglienza
che vorrebbero con questi mezzi.
Andrew Morton da questo consiglio agli aspiranti sviluppatori kernel
::
Il primo progetto per un neofita del kernel dovrebbe essere
sicuramente quello di "assicurarsi che il kernel funzioni alla
perfezione sempre e su tutte le macchine sulle quali potete stendere
la vostra mano". Solitamente il modo per fare ciò è quello di
collaborare con gli altri nel sistemare le cose (questo richiede
persistenza!) ma va bene - è parte dello sviluppo kernel.
(http://lwn.net/Articles/283982/).
In assenza di problemi ovvi da risolvere, si consiglia agli sviluppatori
di consultare, in generale, la lista di regressioni e di bachi aperti.
Non c'è mai carenza di problematiche bisognose di essere sistemate;
accollandosi tali questioni gli sviluppatori accumuleranno esperienza con
la procedura, ed allo stesso tempo, aumenteranno la loro rispettabilità
all'interno della comunità di sviluppo.
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/3.Early-stage.rst <development_early_stage>`
:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>
.. _it_development_early_stage:
Primi passi della pianificazione
================================
I primi passi della pianificazione
==================================
.. warning::
Osservando un progetto di sviluppo per il kernel Linux, si potrebbe essere
tentati dal saltare tutto e iniziare a codificare. Tuttavia, come ogni
progetto significativo, molta della preparazione per giungere al successo
viene fatta prima che una sola linea di codice venga scritta. Il tempo speso
nella pianificazione e la comunicazione può far risparmiare molto
tempo in futuro.
TODO ancora da tradurre
Specificare il problema
-----------------------
Come qualsiasi progetto ingegneristico, un miglioramento del kernel di
successo parte con una chiara descrizione del problema da risolvere.
In alcuni casi, questo passaggio è facile: ad esempio quando un driver è
richiesto per un particolare dispositivo. In altri casi invece, si
tende a confondere il problema reale con le soluzioni proposte e questo
può portare all'emergere di problemi.
Facciamo un esempio: qualche anno fa, gli sviluppatori che lavoravano con
linux audio cercarono un modo per far girare le applicazioni senza dropouts
o altri artefatti dovuti all'eccessivo ritardo nel sistema. La soluzione
alla quale giunsero fu un modulo del kernel destinato ad agganciarsi al
framework Linux Security Module (LSM); questo modulo poteva essere
configurato per dare ad una specifica applicazione accesso allo
schedulatore *realtime*. Tale modulo fu implementato e inviato nella
lista di discussione linux-kernel, dove incontrò subito dei problemi.
Per gli sviluppatori audio, questo modulo di sicurezza era sufficiente a
risolvere il loro problema nell'immediato. Per l'intera comunità kernel,
invece, era un uso improprio del framework LSM (che non è progettato per
conferire privilegi a processi che altrimenti non avrebbero potuto ottenerli)
e un rischio per la stabilità del sistema. Le loro soluzioni di punta nel
breve periodo, comportavano un accesso alla schedulazione realtime attraverso
il meccanismo rlimit, e nel lungo periodo un costante lavoro nella riduzione
dei ritardi.
La comunità audio, comunque, non poteva vedere al di là della singola
soluzione che avevano implementato; erano riluttanti ad accettare alternative.
Il conseguente dissenso lasciò in quegli sviluppatori un senso di
disillusione nei confronti dell'intero processo di sviluppo; uno di loro
scrisse questo messaggio:
Ci sono numerosi sviluppatori del kernel Linux davvero bravi, ma
rischiano di restare sovrastati da una vasta massa di stolti arroganti.
Cercare di comunicare le richieste degli utenti a queste persone è
una perdita di tempo. Loro sono troppo "intelligenti" per stare ad
ascoltare dei poveri mortali.
(http://lwn.net/Articles/131776/).
La realtà delle cose fu differente; gli sviluppatori del kernel erano molto
più preoccupati per la stabilità del sistema, per la manutenzione di lungo
periodo e cercavano la giusta soluzione alla problematica esistente con uno
specifico modulo. La morale della storia è quella di concentrarsi sul
problema - non su di una specifica soluzione- e di discuterne con la comunità
di sviluppo prima di investire tempo nella scrittura del codice.
Quindi, osservando un progetto di sviluppo del kernel, si dovrebbe
rispondere a questa lista di domande:
- Qual'è, precisamente, il problema che dev'essere risolto?
- Chi sono gli utenti coinvolti da tal problema? A quale caso dovrebbe
essere indirizzata la soluzione?
- In che modo il kernel risulta manchevole nell'indirizzare il problema
in questione?
Solo dopo ha senso iniziare a considerare le possibili soluzioni.
Prime discussioni
-----------------
Quando si pianifica un progetto di sviluppo per il kernel, sarebbe quanto meno
opportuno discuterne inizialmente con la comunità prima di lanciarsi
nell'implementazione. Una discussione preliminare può far risparmiare sia
tempo che problemi in svariati modi:
- Potrebbe essere che il problema sia già stato risolto nel kernel in
una maniera che non avete ancora compreso. Il kernel Linux è grande e ha
una serie di funzionalità e capacità che non sono scontate nell'immediato.
Non tutte le capacità del kernel sono documentate così bene come ci
piacerebbe, ed è facile perdersi qualcosa. Il vostro autore ha assistito
alla pubblicazione di un driver intero che duplica un altro driver
esistente di cui il nuovo autore era ignaro. Il codice che rinnova
ingranaggi già esistenti non è soltanto dispendioso; non verrà nemmeno
accettato nel ramo principale del kernel.
- Potrebbero esserci proposte che non sono considerate accettabili per
l'integrazione all'interno del ramo principale. È meglio affrontarle
prima di scrivere il codice.
- È possibile che altri sviluppatori abbiano pensato al problema; potrebbero
avere delle idee per soluzioni migliori, e potrebbero voler contribuire
alla loro creazione.
Anni di esperienza con la comunità di sviluppo del kernel hanno impartito una
chiara lezione: il codice per il kernel che è pensato e sviluppato a porte
chiuse, inevitabilmente, ha problematiche che si rivelano solo quando il
codice viene rilasciato pubblicamente. Qualche volta tali problemi sono
importanti e richiedono mesi o anni di sforzi prima che il codice possa
raggiungere gli standard richiesti della comunità.
Alcuni esempi possono essere:
- La rete Devicescape è stata creata e implementata per sistemi
mono-processore. Non avrebbe potuto essere inserita nel ramo principale
fino a che non avesse supportato anche i sistemi multi-processore.
Riadattare i meccanismi di sincronizzazione e simili è un compito difficile;
come risultato, l'inserimento di questo codice (ora chiamato mac80211)
fu rimandato per più di un anno.
- Il filesystem Reiser4 include una seria di funzionalità che, secondo
l'opinione degli sviluppatori principali del kernel, avrebbero dovuto
essere implementate a livello di filesystem virtuale. Comprende
anche funzionalità che non sono facilmente implementabili senza esporre
il sistema al rischio di uno stallo. La scoperta tardiva di questi
problemi - e il diniego a risolverne alcuni - ha avuto come conseguenza
il fatto che Raiser4 resta fuori dal ramo principale del kernel.
- Il modulo di sicurezza AppArmor utilizzava strutture dati del
filesystem virtuale interno in modi che sono stati considerati rischiosi e
inattendibili. Questi problemi (tra le altre cose) hanno tenuto AppArmor
fuori dal ramo principale per anni.
Ciascuno di questi casi è stato un travaglio e ha richiesto del lavoro
straordinario, cose che avrebbero potuto essere evitate con alcune
"chiacchierate" preliminari con gli sviluppatori kernel.
Con chi parlare?
----------------
Quando gli sviluppatori hanno deciso di rendere pubblici i propri progetti, la
domanda successiva sarà: da dove partiamo? La risposta è quella di trovare
la giusta lista di discussione e il giusto manutentore. Per le liste di
discussione, il miglior approccio è quello di cercare la lista più adatta
nel file MAINTAINERS. Se esiste una lista di discussione di sottosistema,
è preferibile pubblicare lì piuttosto che sulla lista di discussione generale
del kernel Linux; avrete maggiori probabilità di trovare sviluppatori con
esperienza sul tema, e l'ambiente che troverete potrebbe essere più
incoraggiante.
Trovare manutentori può rivelarsi un po' difficoltoso. Ancora, il file
MAINTAINERS è il posto giusto da dove iniziare. Il file potrebbe non essere
sempre aggiornato, inoltre, non tutti i sottosistemi sono rappresentati qui.
Coloro che sono elencati nel file MAINTAINERS potrebbero, in effetti, non
essere le persone che attualmente svolgono quel determinato ruolo. Quindi,
quando c'è un dubbio su chi contattare, un trucco utile è quello di usare
git (git log in particolare) per vedere chi attualmente è attivo all'interno
del sottosistema interessato. Controllate chi sta scrivendo le patch,
e chi, se non ci fosse nessuno, sta aggiungendo la propria firma
(Signed-off-by) a quelle patch. Quelle sono le persone maggiormente
qualificate per aiutarvi con lo sviluppo di nuovo progetto.
Il compito di trovare il giusto manutentore, a volte, è una tale sfida che
ha spinto gli sviluppatori del kernel a scrivere uno script che li aiutasse
in questa ricerca:
::
.../scripts/get_maintainer.pl
Se questo script viene eseguito con l'opzione "-f" ritornerà il
manutentore(i) attuale per un dato file o cartella. Se viene passata una
patch sulla linea di comando, lo script elencherà i manutentori che
dovrebbero riceverne una copia. Ci sono svariate opzioni che regolano
quanto a fondo get_maintainer.pl debba cercare i manutentori;
siate quindi prudenti nell'utilizzare le opzioni più aggressive poiché
potreste finire per includere sviluppatori che non hanno un vero interesse
per il codice che state modificando.
Se tutto ciò dovesse fallire, parlare con Andrew Morton potrebbe essere
un modo efficace per capire chi è il manutentore di un dato pezzo di codice.
Quando pubblicare
-----------------
Se potete, pubblicate i vostri intenti durante le fasi preliminari, sarà
molto utile. Descrivete il problema da risolvere e ogni piano che è stato
elaborato per l'implementazione. Ogni informazione fornita può aiutare
la comunità di sviluppo a fornire spunti utili per il progetto.
Un evento che potrebbe risultare scoraggiate e che potrebbe accadere in
questa fase non è il ricevere una risposta ostile, ma, invece, ottenere
una misera o inesistente reazione. La triste verità è che: (1) gli
sviluppatori del kernel tendono ad essere occupati, (2) ci sono tante persone
con grandi progetti e poco codice (o anche solo la prospettiva di
avere un codice) a cui riferirsi e (3) nessuno è obbligato a revisionare
o a fare osservazioni in merito ad idee pubblicate da altri. Oltre a
questo, progetti di alto livello spesso nascondono problematiche che si
rivelano solo quando qualcuno cerca di implementarle; per questa ragione
gli sviluppatori kernel preferirebbero vedere il codice.
Quindi, se una richiesta pubblica di commenti riscuote poco successo, non
pensate che ciò significhi che non ci sia interesse nel progetto.
Sfortunatamente, non potete nemmeno assumere che non ci siano problemi con
la vostra idea. La cosa migliore da fare in questa situazione è quella di
andare avanti e tenere la comunità informata mentre procedete.
Ottenere riscontri ufficiali
----------------------------
Se il vostro lavoro è stato svolto in un ambiente aziendale - come molto
del lavoro fatto su Linux - dovete, ovviamente, avere il permesso dei
dirigenti prima che possiate pubblicare i progetti, o il codice aziendale,
su una lista di discussione pubblica. La pubblicazione di codice che non
è stato rilascio espressamente con licenza GPL-compatibile può rivelarsi
problematico; prima la dirigenza, e il personale legale, troverà una decisione
sulla pubblicazione di un progetto, meglio sarà per tutte le persone coinvolte.
A questo punto, alcuni lettori potrebbero pensare che il loro lavoro sul
kernel è preposto a supportare un prodotto che non è ancora ufficialmente
riconosciuto. Rivelare le intenzioni dei propri datori di lavori in una
lista di discussione pubblica potrebbe non essere una soluzione valida.
In questi casi, vale la pena considerare se la segretezza sia necessaria
o meno; spesso non c'è una reale necessità di mantenere chiusi i progetti di
sviluppo.
Detto ciò, ci sono anche casi dove l'azienda legittimamente non può rivelare
le proprie intenzioni in anticipo durante il processo di sviluppo. Le aziende
che hanno sviluppatori kernel esperti possono scegliere di procedere a
carte coperte partendo dall'assunto che saranno in grado di evitare, o gestire,
in futuro, eventuali problemi d'integrazione. Per le aziende senza questo tipo
di esperti, la migliore opzione è spesso quella di assumere uno sviluppatore
esterno che revisioni i progetti con un accordo di segretezza.
La Linux Foundation applica un programma di NDA creato appositamente per
aiutare le aziende in questa particolare situazione; potrete trovare più
informazioni sul sito:
http://www.linuxfoundation.org/en/NDA_program
Questa tipologia di revisione è spesso sufficiente per evitare gravi problemi
senza che sia richiesta l'esposizione pubblica del progetto.
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/4.Coding.rst <development_coding>`
:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>
.. _it_development_coding:
Scrivere codice corretto
========================
.. warning::
Nonostante ci sia molto da dire sul processo di creazione, sulla sua solidità
e sul suo orientamento alla comunità, la prova di ogni progetto di sviluppo
del kernel si trova nel codice stesso. È il codice che sarà esaminato dagli
altri sviluppatori ed inserito (o no) nel ramo principale. Quindi è la
qualità di questo codice che determinerà il successo finale del progetto.
TODO ancora da tradurre
Questa sezione esaminerà il processo di codifica. Inizieremo con uno sguardo
sulle diverse casistiche nelle quali gli sviluppatori kernel possono
sbagliare. Poi, l'attenzione si sposterà verso "il fare le cose
correttamente" e sugli strumenti che possono essere utili in questa missione.
Trappole
--------
Lo stile del codice
*******************
Il kernel ha da tempo delle norme sullo stile di codifica che sono descritte in
:ref:`Documentation/translations/it_IT/process/coding-style.rst <codingstyle>`.
Per la maggior parte del tempo, la politica descritta in quel file è stata
praticamente informativa. Ne risulta che ci sia una quantità sostanziale di
codice nel kernel che non rispetta le linee guida relative allo stile.
La presenza di quel codice conduce a due distinti pericoli per gli
sviluppatori kernel.
Il primo di questi è credere che gli standard di codifica del kernel
non sono importanti e possono non essere applicati. La verità è che
aggiungere nuovo codice al kernel è davvero difficile se questo non
rispetta le norme; molti sviluppatori richiederanno che il codice sia
riformulato prima che anche solo lo revisionino. Una base di codice larga
quanto il kernel richiede una certa uniformità, in modo da rendere possibile
per gli sviluppatori una comprensione veloce di ogni sua parte. Non ci sono,
quindi, più spazi per un codice formattato alla carlona.
Occasionalmente, lo stile di codifica del kernel andrà in conflitto con lo
stile richiesto da un datore di lavoro. In alcuni casi, lo stile del kernel
dovrà prevalere prima che il codice venga inserito. Mettere il codice
all'interno del kernel significa rinunciare a un certo grado di controllo
in differenti modi - incluso il controllo sul come formattare il codice.
L’altra trappola è quella di pensare che il codice già presente nel kernel
abbia urgentemente bisogno di essere sistemato. Gli sviluppatori potrebbero
iniziare a generare patch che correggono lo stile come modo per prendere
famigliarità con il processo, o come modo per inserire i propri nomi nei
changelog del kernel – o entrambe. La comunità di sviluppo vede un attività
di codifica puramente correttiva come "rumore"; queste attività riceveranno
una fredda accoglienza. Di conseguenza è meglio evitare questo tipo di patch.
Mentre si lavora su un pezzo di codice è normale correggerne anche lo stile,
ma le modifiche di stile non dovrebbero essere fatte fini a se stesse.
Il documento sullo stile del codice non dovrebbe essere letto come una legge
assoluta che non può mai essere trasgredita. Se c’è un a buona ragione
(per esempio, una linea che diviene poco leggibile se divisa per rientrare
nel limite di 80 colonne), fatelo e basta.
Notate che potete utilizzare lo strumento “clang-format” per aiutarvi con
le regole, per una riformattazione automatica e veloce del vostro codice
e per revisionare interi file per individuare errori nello stile di codifica,
refusi e possibili miglioramenti. Inoltre è utile anche per classificare gli
``#includes``, per allineare variabili/macro, per testi derivati ed altri
compiti del genere. Consultate il file
:ref:`Documentation/translations/it_IT/process/clang-format.rst <clangformat>`
per maggiori dettagli
Livelli di astrazione
*********************
I professori di Informatica insegnano ai propri studenti a fare ampio uso dei
livelli di astrazione nel nome della flessibilità e del nascondere informazioni.
Certo il kernel fa un grande uso dell'astrazione; nessun progetto con milioni
di righe di codice potrebbe fare altrimenti e sopravvivere. Ma l'esperienza
ha dimostrato che un'eccessiva o prematura astrazione può rivelarsi dannosa
al pari di una prematura ottimizzazione. L'astrazione dovrebbe essere usata
fino al livello necessario e non oltre.
Ad un livello base, considerate una funzione che ha un argomento che viene
sempre impostato a zero da tutti i chiamanti. Uno potrebbe mantenere
quell'argomento nell'eventualità qualcuno volesse sfruttare la flessibilità
offerta. In ogni caso, tuttavia, ci sono buone possibilità che il codice
che va ad implementare questo argomento aggiuntivo, sia stato rotto in maniera
sottile, in un modo che non è mai stato notato - perché non è mai stato usato.
Oppure, quando sorge la necessità di avere più flessibilità, questo argomento
non la fornisce in maniera soddisfacente. Gli sviluppatori di Kernel,
sottopongono costantemente patch che vanno a rimuovere gli argomenti
inutilizzate; anche se, in generale, non avrebbero dovuto essere aggiunti.
I livelli di astrazione che nascondono l'accesso all'hardware -
spesso per poter usare dei driver su diversi sistemi operativi - vengono
particolarmente disapprovati. Tali livelli oscurano il codice e possono
peggiorare le prestazioni; essi non appartengono al kernel Linux.
D'altro canto, se vi ritrovate a dover copiare una quantità significativa di
codice proveniente da un altro sottosistema del kernel, è tempo di chiedersi
se, in effetti, non avrebbe più senso togliere parte di quel codice e metterlo
in una libreria separata o di implementare quella funzionalità ad un livello
più elevato. Non c'è utilità nel replicare lo stesso codice per tutto
il kernel.
#ifdef e l'uso del preprocessore in generale
********************************************
Il preprocessore C sembra essere una fonte di attrazione per qualche
programmatore C, che ci vede una via per ottenere una grande flessibilità
all'interno di un file sorgente. Ma il preprocessore non è scritto in C,
e un suo massiccio impiego conduce a un codice che è molto più difficile
da leggere per gli altri e che rende più difficile il lavoro di verifica del
compilatore. L'uso eccessivo del preprocessore è praticamente sempre il segno
di un codice che necessita di un certo lavoro di pulizia.
La compilazione condizionata con #ifdef è, in effetti, un potente strumento,
ed esso viene usato all'interno del kernel. Ma esiste un piccolo desiderio:
quello di vedere il codice coperto solo da una leggera spolverata di
blocchi #ifdef. Come regola generale, quando possibile, l'uso di #ifdef
dovrebbe essere confinato nei file d'intestazione. Il codice compilato
condizionatamente può essere confinato a funzioni tali che, nel caso in cui
il codice non deve essere presente, diventano vuote. Il compilatore poi
ottimizzerà la chiamata alla funzione vuota rimuovendola. Il risultato è
un codice molto più pulito, più facile da seguire.
Le macro del preprocessore C presentano una serie di pericoli, inclusi
valutazioni multiple di espressioni che hanno effetti collaterali e non
garantiscono una sicurezza rispetto ai tipi. Se siete tentati dal definire
una macro, considerate l'idea di creare invece una funzione inline. Il codice
che ne risulterà sarà lo stesso, ma le funzioni inline sono più leggibili,
non considerano i propri argomenti più volte, e permettono al compilatore di
effettuare controlli sul tipo degli argomenti e del valore di ritorno.
Funzioni inline
***************
Comunque, anche le funzioni inline hanno i loro pericoli. I programmatori
potrebbero innamorarsi dell'efficienza percepita derivata dalla rimozione
di una chiamata a funzione. Queste funzioni, tuttavia, possono ridurre le
prestazioni. Dato che il loro codice viene replicato ovunque vi sia una
chiamata ad esse, si finisce per gonfiare le dimensioni del kernel compilato.
Questi, a turno, creano pressione sulla memoria cache del processore, e questo
può causare rallentamenti importanti. Le funzioni inline, di norma, dovrebbero
essere piccole e usate raramente. Il costo di una chiamata a funzione, dopo
tutto, non è così alto; la creazione di molte funzioni inline è il classico
esempio di un'ottimizzazione prematura.
In generale, i programmatori del kernel ignorano gli effetti della cache a
loro rischio e pericolo. Il classico compromesso tempo/spazio teorizzato
all'inizio delle lezioni sulle strutture dati spesso non si applica
all'hardware moderno. Lo spazio *è* tempo, in questo senso un programma
più grande sarà più lento rispetto ad uno più compatto.
I compilatori più recenti hanno preso un ruolo attivo nel decidere se
una data funzione deve essere resa inline oppure no. Quindi l'uso
indiscriminato della parola chiave "inline" potrebbe non essere non solo
eccessivo, ma anche irrilevante.
Sincronizzazione
****************
Nel maggio 2006, il sistema di rete "Devicescape" fu rilasciato in pompa magna
sotto la licenza GPL e reso disponibile per la sua inclusione nella ramo
principale del kernel. Questa donazione fu una notizia bene accolta;
il supporto per le reti senza fili era considerata, nel migliore dei casi,
al di sotto degli standard; il sistema Deviscape offrì la promessa di una
risoluzione a tale situazione. Tuttavia, questo codice non fu inserito nel
ramo principale fino al giugno del 2007 (2.6.22). Cosa accadde?
Quel codice mostrava numerosi segnali di uno sviluppo in azienda avvenuto
a porte chiuse. Ma in particolare, un grosso problema fu che non fu
progettato per girare in un sistema multiprocessore. Prima che questo
sistema di rete (ora chiamato mac80211) potesse essere inserito, fu necessario
un lavoro sugli schemi di sincronizzazione.
Una volta, il codice del kernel Linux poteva essere sviluppato senza pensare
ai problemi di concorrenza presenti nei sistemi multiprocessore. Ora,
comunque, questo documento è stato scritto su di un portatile dual-core.
Persino su sistemi a singolo processore, il lavoro svolto per incrementare
la capacità di risposta aumenterà il livello di concorrenza interno al kernel.
I giorni nei quali il codice poteva essere scritto senza pensare alla
sincronizzazione sono da passati tempo.
Ogni risorsa (strutture dati, registri hardware, etc.) ai quali si potrebbe
avere accesso simultaneo da più di un thread deve essere sincronizzato. Il
nuovo codice dovrebbe essere scritto avendo tale accortezza in testa;
riadattare la sincronizzazione a posteriori è un compito molto più difficile.
Gli sviluppatori del kernel dovrebbero prendersi il tempo di comprendere bene
le primitive di sincronizzazione, in modo da sceglier lo strumento corretto
per eseguire un compito. Il codice che presenta una mancanza di attenzione
alla concorrenza avrà un percorso difficile all'interno del ramo principale.
Regressioni
***********
Vale la pena menzionare un ultimo pericolo: potrebbe rivelarsi accattivante
l'idea di eseguire un cambiamento (che potrebbe portare a grandi
miglioramenti) che porterà ad alcune rotture per gli utenti esistenti.
Questa tipologia di cambiamento è chiamata "regressione", e le regressioni son
diventate mal viste nel ramo principale del kernel. Con alcune eccezioni,
i cambiamenti che causano regressioni saranno fermati se quest'ultime non
potranno essere corrette in tempo utile. È molto meglio quindi evitare
la regressione fin dall'inizio.
Spesso si è argomentato che una regressione può essere giustificata se essa
porta risolve più problemi di quanti non ne crei. Perché, dunque, non fare
un cambiamento se questo porta a nuove funzionalità a dieci sistemi per
ognuno dei quali esso determina una rottura? La migliore risposta a questa
domanda ci è stata fornita da Linus nel luglio 2007:
::
Dunque, noi non sistemiamo bachi introducendo nuovi problemi. Quella
via nasconde insidie, e nessuno può sapere del tutto se state facendo
dei progressi reali. Sono due passi avanti e uno indietro, oppure
un passo avanti e due indietro?
(http://lwn.net/Articles/243460/).
Una particolare tipologia di regressione mal vista consiste in una qualsiasi
sorta di modifica all'ABI dello spazio utente. Una volta che un'interfaccia
viene esportata verso lo spazio utente, dev'essere supportata all'infinito.
Questo fatto rende la creazione di interfacce per lo spazio utente
particolarmente complicato: dato che non possono venir cambiate introducendo
incompatibilità, esse devono essere fatte bene al primo colpo. Per questa
ragione sono sempre richieste: ampie riflessioni, documentazione chiara e
ampie revisioni dell'interfaccia verso lo spazio utente.
Strumenti di verifica del codice
--------------------------------
Almeno per ora la scrittura di codice priva di errori resta un ideale
irraggiungibile ai più. Quello che speriamo di poter fare, tuttavia, è
trovare e correggere molti di questi errori prima che il codice entri nel
ramo principale del kernel. A tal scopo gli sviluppatori del kernel devono
mettere insieme una schiera impressionante di strumenti che possano
localizzare automaticamente un'ampia varietà di problemi. Qualsiasi problema
trovato dal computer è un problema che non affliggerà l'utente in seguito,
ne consegue che gli strumenti automatici dovrebbero essere impiegati ovunque
possibile.
Il primo passo consiste semplicemente nel fare attenzione agli avvertimenti
proveniente dal compilatore. Versioni moderne di gcc possono individuare
(e segnalare) un gran numero di potenziali errori. Molto spesso, questi
avvertimenti indicano problemi reali. Di regola, il codice inviato per la
revisione non dovrebbe produrre nessun avvertimento da parte del compilatore.
Per mettere a tacere gli avvertimenti, cercate di comprenderne le cause reali
e cercate di evitare le "riparazioni" che fan sparire l'avvertimento senza
però averne trovato la causa.
Tenete a mente che non tutti gli avvertimenti sono disabilitati di default.
Costruite il kernel con "make EXTRA_CFLAGS=-W" per ottenerli tutti.
Il kernel fornisce differenti opzioni che abilitano funzionalità di debugging;
molti di queste sono trovano all'interno del sotto menu "kernel hacking".
La maggior parte di queste opzioni possono essere attivate per qualsiasi
kernel utilizzato per lo sviluppo o a scopo di test. In particolare dovreste
attivare:
- ENABLE_WARN_DEPRECATED, ENABLE_MUST_CHECK, e FRAME_WARN per ottenere degli
avvertimenti dedicati a problemi come l'uso di interfacce deprecate o
l'ignorare un importante valore di ritorno di una funzione. Il risultato
generato da questi avvertimenti può risultare verboso, ma non bisogna
preoccuparsi per gli avvertimenti provenienti da altre parti del kernel.
- DEBUG_OBJECTS aggiungerà un codice per tracciare il ciclo di vita di
diversi oggetti creati dal kernel e avvisa quando qualcosa viene eseguito
fuori controllo. Se state aggiungendo un sottosistema che crea (ed
esporta) oggetti complessi propri, considerate l'aggiunta di un supporto
al debugging dell'oggetto.
- DEBUG_SLAB può trovare svariati errori di uso e di allocazione di memoria;
esso dovrebbe esser usato dalla maggior parte dei kernel di sviluppo.
- DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP, e DEBUG_MUTEXES troveranno un certo
numero di errori comuni di sincronizzazione.
Esistono ancora delle altre opzioni di debugging, di alcune di esse
discuteremo qui sotto. Alcune di esse hanno un forte impatto e non dovrebbero
essere usate tutte le volte. Ma qualche volta il tempo speso nell'capire
le opzioni disponibili porterà ad un risparmio di tempo nel breve termine.
Uno degli strumenti di debugging più tosti è il *locking checker*, o
"lockdep". Questo strumento traccerà qualsiasi acquisizione e rilascio di
ogni *lock* (spinlock o mutex) nel sistema, l'ordine con il quale i *lock*
sono acquisiti in relazione l'uno con l'altro, l'ambiente corrente di
interruzione, eccetera. Inoltre esso può assicurare che i *lock* vengano
acquisiti sempre nello stesso ordine, che le stesse assunzioni sulle
interruzioni si applichino in tutte le occasioni, e così via. In altre parole,
lockdep può scovare diversi scenari nei quali il sistema potrebbe, in rari
casi, trovarsi in stallo. Questa tipologia di problema può essere grave
(sia per gli sviluppatori che per gli utenti) in un sistema in uso; lockdep
permette di trovare tali problemi automaticamente e in anticipo.
In qualità di programmatore kernel diligente, senza dubbio, dovrete controllare
il valore di ritorno di ogni operazione (come l'allocazione della memoria)
poiché esso potrebbe fallire. Il nocciolo della questione è che i percorsi
di gestione degli errori, con grande probabilità, non sono mai stati
collaudati del tutto. Il codice collaudato tende ad essere codice bacato;
potrete quindi essere più a vostro agio con il vostro codice se tutti questi
percorsi fossero stati verificati un po' di volte.
Il kernel fornisce un framework per l'inserimento di fallimenti che fa
esattamente al caso, specialmente dove sono coinvolte allocazioni di memoria.
Con l'opzione per l'inserimento dei fallimenti abilitata, una certa percentuale
di allocazione di memoria sarà destinata al fallimento; questi fallimenti
possono essere ridotti ad uno specifico pezzo di codice. Procedere con
l'inserimento dei fallimenti attivo permette al programmatore di verificare
come il codice risponde quando le cose vanno male. Consultate:
Documentation/fault-injection/fault-injection.txt per avere maggiori
informazioni su come utilizzare questo strumento.
Altre tipologie di errori possono essere riscontrati con lo strumento di
analisi statica "sparse". Con Sparse, il programmatore può essere avvisato
circa la confusione tra gli indirizzi dello spazio utente e dello spazio
kernel, un miscuglio fra quantità big-endian e little-endian, il passaggio
di un valore intero dove ci sia aspetta un gruppo di flag, e così via.
Sparse deve essere installato separatamente (se il vostra distribuzione non
lo prevede, potete trovarlo su https://sparse.wiki.kernel.org/index.php/Main_Page);
può essere attivato sul codice aggiungendo "C=1" al comando make.
Lo strumento "Coccinelle" (http://coccinelle.lip6.fr/) è in grado di trovare
una vasta varietà di potenziali problemi di codifica; e può inoltre proporre
soluzioni per risolverli. Un buon numero di "patch semantiche" per il kernel
sono state preparate nella cartella scripts/coccinelle; utilizzando
"make coccicheck" esso percorrerà tali patch semantiche e farà rapporto su
qualsiasi problema trovato. Per maggiori informazioni, consultate
:ref:`Documentation/dev-tools/coccinelle.rst <devtools_coccinelle>`.
Altri errori di portabilità sono meglio scovati compilando il vostro codice
per altre architetture. Se non vi accade di avere un sistema S/390 o una
scheda di sviluppo Blackfin sotto mano, potete comunque continuare la fase
di compilazione. Un vasto numero di cross-compilatori per x86 possono
essere trovati al sito:
http://www.kernel.org/pub/tools/crosstool/
Il tempo impiegato nell'installare e usare questi compilatori sarà d'aiuto
nell'evitare situazioni imbarazzanti nel futuro.
Documentazione
--------------
La documentazione è spesso stata più un'eccezione che una regola nello
sviluppo del kernel. Nonostante questo, un'adeguata documentazione aiuterà
a facilitare l'inserimento di nuovo codice nel kernel, rende la vita più
facile per gli altri sviluppatori e sarà utile per i vostri utenti. In molti
casi, la documentazione è divenuta sostanzialmente obbligatoria.
La prima parte di documentazione per qualsiasi patch è il suo changelog.
Questi dovrebbero descrivere le problematiche risolte, la tipologia di
soluzione, le persone che lavorano alla patch, ogni effetto rilevante
sulle prestazioni e tutto ciò che può servire per la comprensione della
patch. Assicuratevi che il changelog dica *perché*, vale la pena aggiungere
la patch; un numero sorprendente di sviluppatori sbaglia nel fornire tale
informazione.
Qualsiasi codice che aggiunge una nuova interfaccia in spazio utente - inclusi
nuovi file in sysfs o /proc - dovrebbe includere la documentazione di tale
interfaccia così da permette agli sviluppatori dello spazio utente di sapere
con cosa stanno lavorando. Consultate: Documentation/ABI/README per avere una
descrizione di come questi documenti devono essere impostati e quali
informazioni devono essere fornite.
Il file :ref:`Documentation/translations/it_IT/admin-guide/kernel-parameters.rst <kernelparameters>`
descrive tutti i parametri di avvio del kernel. Ogni patch che aggiunga
nuovi parametri dovrebbe aggiungere nuove voci a questo file.
Ogni nuova configurazione deve essere accompagnata da un testo di supporto
che spieghi chiaramente le opzioni e spieghi quando l'utente potrebbe volerle
selezionare.
Per molti sottosistemi le informazioni sull'API interna sono documentate sotto
forma di commenti formattati in maniera particolare; questi commenti possono
essere estratti e formattati in differenti modi attraverso lo script
"kernel-doc". Se state lavorando all'interno di un sottosistema che ha
commenti kerneldoc dovreste mantenerli e aggiungerli, in maniera appropriata,
per le funzioni disponibili esternamente. Anche in aree che non sono molto
documentate, non c'è motivo per non aggiungere commenti kerneldoc per il
futuro; infatti, questa può essere un'attività utile per sviluppatori novizi
del kernel. Il formato di questi commenti, assieme alle informazione su come
creare modelli per kerneldoc, possono essere trovati in
:ref:`Documentation/translations/it_IT/doc-guide/ <doc_guide>`.
Chiunque legga un ammontare significativo di codice kernel noterà che, spesso,
i commenti si fanno maggiormente notare per la loro assenza. Ancora una volta,
le aspettative verso il nuovo codice sono più alte rispetto al passato;
inserire codice privo di commenti sarà più difficile. Detto ciò, va aggiunto
che non si desiderano commenti prolissi per il codice. Il codice dovrebbe
essere, di per sé, leggibile, con dei commenti che spieghino gli aspetti più
sottili.
Determinate cose dovrebbero essere sempre commentate. L'uso di barriere
di memoria dovrebbero essere accompagnate da una riga che spieghi perché sia
necessaria. Le regole di sincronizzazione per le strutture dati, generalmente,
necessitano di una spiegazioni da qualche parte. Le strutture dati più
importanti, in generale, hanno bisogno di una documentazione onnicomprensiva.
Le dipendenze che non sono ovvie tra bit separati di codice dovrebbero essere
indicate. Tutto ciò che potrebbe indurre un inserviente del codice a fare
una "pulizia" incorretta, ha bisogno di un commento che dica perché è stato
fatto in quel modo. E così via.
Cambiamenti interni dell'API
----------------------------
L'interfaccia binaria fornita dal kernel allo spazio utente non può essere
rotta tranne che in circostanze eccezionali. L'interfaccia di programmazione
interna al kernel, invece, è estremamente fluida e può essere modificata al
bisogno. Se vi trovate a dover lavorare attorno ad un'API del kernel o
semplicemente non state utilizzando una funzionalità offerta perché questa
non rispecchia i vostri bisogni, allora questo potrebbe essere un segno che
l'API ha bisogno di essere cambiata. In qualità di sviluppatore del kernel,
hai il potere di fare questo tipo di modifica.
Ci sono ovviamente alcuni punti da cogliere. I cambiamenti API possono essere
fatti, ma devono essere giustificati. Quindi ogni patch che porta ad una
modifica dell'API interna dovrebbe essere accompagnata da una descrizione
della modifica in sé e del perché essa è necessaria. Questo tipo di
cambiamenti dovrebbero, inoltre, essere fatti in una patch separata, invece di
essere sepolti all'interno di una patch più grande.
L'altro punto da cogliere consiste nel fatto che uno sviluppatore che
modifica l'API deve, in generale, essere responsabile della correzione
di tutto il codice del kernel che viene rotto per via della sua modifica.
Per una funzione ampiamente usata, questo compito può condurre letteralmente
a centinaia o migliaia di modifiche, molte delle quali sono in conflitto con
il lavoro svolto da altri sviluppatori. Non c'è bisogno di dire che questo
può essere un lavoro molto grosso, quindi è meglio essere sicuri che la
motivazione sia ben solida. Notate che lo strumento Coccinelle può fornire
un aiuto con modifiche estese dell'API.
Quando viene fatta una modifica API incompatibile, una persona dovrebbe,
quando possibile, assicurarsi che quel codice non aggiornato sia trovato
dal compilatore. Questo vi aiuterà ad essere sicuri d'avere trovato,
tutti gli usi di quell'interfaccia. Inoltre questo avviserà gli sviluppatori
di codice fuori dal kernel che c'è un cambiamento per il quale è necessario del
lavoro. Il supporto al codice fuori dal kernel non è qualcosa di cui gli
sviluppatori del kernel devono preoccuparsi, ma non dobbiamo nemmeno rendere
più difficile del necessario la vita agli sviluppatori di questo codice.
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/4.Posting.rst <development_posting>`
:Original: :ref:`Documentation/process/5.Posting.rst <development_posting>`
:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
.. _it_development_posting:
Pubblicare modifiche
====================
.. warning::
Prima o poi arriva il momento in cui il vostro lavoro è pronto per essere
presentato alla comunità per una revisione ed eventualmente per la sua
inclusione nel ramo principale del kernel. Com'era prevedibile,
la comunità di sviluppo del kernel ha elaborato un insieme di convenzioni
e di procedure per la pubblicazione delle patch; seguirle renderà la vita
più facile a tutti quanti. Questo documento cercherà di coprire questi
argomenti con un ragionevole livello di dettaglio; più informazioni possono
essere trovare nella cartella 'Documentation', nei file
:ref:`translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`,
:ref:`translations/it_IT/process/submitting-drivers.rst <it_submittingdrivers>`, e
:ref:`translations/it_IT/process/submit-checklist.rst <it_submitchecklist>`.
TODO ancora da tradurre
Quando pubblicarle
------------------
C'è sempre una certa resistenza nel pubblicare patch finché non sono
veramente "pronte". Per semplici patch questo non è un problema.
Ma quando il lavoro è di una certa complessità, c'è molto da guadagnare
dai riscontri che la comunità può darvi prima che completiate il lavoro.
Dovreste considerare l'idea di pubblicare un lavoro incompleto, o anche
preparare un ramo git disponibile agli sviluppatori interessati, cosicché
possano stare al passo col vostro lavoro in qualunque momento.
Quando pubblicate del codice che non è considerato pronto per l'inclusione,
è bene che lo diciate al momento della pubblicazione. Inoltre, aggiungete
informazioni sulle cose ancora da sviluppare e sui problemi conosciuti.
Poche persone guarderanno delle patch che si sa essere fatte a metà,
ma quelli che lo faranno penseranno di potervi aiutare a condurre il vostro
sviluppo nella giusta direzione.
Prima di creare patch
---------------------
Ci sono un certo numero di cose che dovreste fare prima di considerare
l'invio delle patch alla comunità di sviluppo. Queste cose includono:
- Verificare il codice fino al massimo che vi è consentito. Usate gli
strumenti di debug del kernel, assicuratevi che il kernel compili con
tutte le più ragionevoli combinazioni d'opzioni, usate cross-compilatori
per compilare il codice per differenti architetture, eccetera.
- Assicuratevi che il vostro codice sia conforme alla linee guida del
kernel sullo stile del codice.
- La vostra patch ha delle conseguenze in termini di prestazioni?
Se è così, dovreste eseguire dei *benchmark* che mostrino il loro
impatto (anche positivo); un riassunto dei risultati dovrebbe essere
incluso nella patch.
- Siate certi d'avere i diritti per pubblicare il codice. Se questo
lavoro è stato fatto per un datore di lavoro, egli avrà dei diritti su
questo lavoro e dovrà quindi essere d'accordo alla sua pubblicazione
con una licenza GPL
Come regola generale, pensarci un po' di più prima di inviare il codice
ripaga quasi sempre lo sforzo.
Preparazione di una patch
-------------------------
La preparazione delle patch per la pubblicazione può richiedere una quantità
di lavoro significativa, ma, ripetiamolo ancora, generalmente sconsigliamo
di risparmiare tempo in questa fase, anche sul breve periodo.
Le patch devono essere preparate per una specifica versione del kernel.
Come regola generale, una patch dovrebbe basarsi sul ramo principale attuale
così come lo si trova nei sorgenti git di Linus. Quando vi basate sul ramo
principale, cominciate da un punto di rilascio ben noto - uno stabile o
un -rc - piuttosto che creare il vostro ramo da quello principale in un punto
a caso.
Per facilitare una revisione e una verifica più estesa, potrebbe diventare
necessaria la produzione di versioni per -mm, linux-next o i sorgenti di un
sottosistema. Basare questa patch sui suddetti sorgenti potrebbe richiedere
un lavoro significativo nella risoluzione dei conflitti e nella correzione dei
cambiamenti di API; questo potrebbe variare a seconda dell'area d'interesse
della vostra patch e da quello che succede altrove nel kernel.
Solo le modifiche più semplici dovrebbero essere preparate come una singola
patch; tutto il resto dovrebbe essere preparato come una serie logica di
modifiche. Spezzettare le patch è un po' un'arte; alcuni sviluppatori
passano molto tempo nel capire come farlo in modo che piaccia alla comunità.
Ci sono alcune regole spannometriche, che comunque possono aiutare
considerevolmente:
- La serie di patch che pubblicherete, quasi sicuramente, non sarà
come quella che trovate nel vostro sistema di controllo di versione.
Invece, le vostre modifiche dovranno essere considerate nella loro forma
finale, e quindi separate in parti che abbiano un senso. Gli sviluppatori
sono interessati in modifiche che siano discrete e indipendenti, non
alla strada che avete percorso per ottenerle.
- Ogni modifica logicamente indipendente dovrebbe essere preparata come una
patch separata. Queste modifiche possono essere piccole ("aggiunto un
campo in questa struttura") o grandi (l'aggiunta di un driver nuovo,
per esempio), ma dovrebbero essere concettualmente piccole da permettere
una descrizione in una sola riga. Ogni patch dovrebbe fare modifiche
specifiche che si possano revisionare indipendentemente e di cui si possa
verificare la veridicità.
- Giusto per riaffermare quando detto sopra: non mischiate diversi tipi di
modifiche nella stessa patch. Se una modifica corregge un baco critico
per la sicurezza, riorganizza alcune strutture, e riformatta il codice,
ci sono buone probabilità che venga ignorata e che la correzione importante
venga persa.
- Ogni modifica dovrebbe portare ad un kernel che compila e funziona
correttamente; se la vostra serie di patch si interrompe a metà il
risultato dovrebbe essere comunque un kernel funzionante. L'applicazione
parziale di una serie di patch è uno scenario comune nel quale il
comando "git bisect" viene usato per trovare delle regressioni; se il
risultato è un kernel guasto, renderete la vita degli sviluppatori più
difficile così come quella di chi s'impegna nel nobile lavoro di
scovare i problemi.
- Però, non strafate. Una volta uno sviluppatore pubblicò una serie di 500
patch che modificavano un unico file - un atto che non lo rese la persona
più popolare sulla lista di discussione del kernel. Una singola patch
può essere ragionevolmente grande fintanto che contenga un singolo
cambiamento *logico*.
- Potrebbe essere allettante l'idea di aggiungere una nuova infrastruttura
come una serie di patch, ma di lasciare questa infrastruttura inutilizzata
finché l'ultima patch della serie non abilita tutto quanto. Quando è
possibile, questo dovrebbe essere evitato; se questa serie aggiunge delle
regressioni, "bisect" indicherà quest'ultima patch come causa del
problema anche se il baco si trova altrove. Possibilmente, quando una
patch aggiunge del nuovo codice dovrebbe renderlo attivo immediatamente.
Lavorare per creare la serie di patch perfetta potrebbe essere frustrante
perché richiede un certo tempo e soprattutto dopo che il "vero lavoro" è
già stato fatto. Quando ben fatto, comunque, è tempo ben speso.
Formattazione delle patch e i changelog
---------------------------------------
Quindi adesso avete una serie perfetta di patch pronte per la pubblicazione,
ma il lavoro non è davvero finito. Ogni patch deve essere preparata con
un messaggio che spieghi al resto del mondo, in modo chiaro e veloce,
il suo scopo. Per ottenerlo, ogni patch sarà composta dai seguenti elementi:
- Un campo opzionale "From" col nome dell'autore della patch. Questa riga
è necessaria solo se state passando la patch di qualcun altro via email,
ma nel dubbio non fa di certo male aggiungerlo.
- Una descrizione di una riga che spieghi cosa fa la patch. Questo
messaggio dovrebbe essere sufficiente per far comprendere al lettore lo
scopo della patch senza altre informazioni. Questo messaggio,
solitamente, presenta in testa il nome del sottosistema a cui si riferisce,
seguito dallo scopo della patch. Per esempio:
::
gpio: fix build on CONFIG_GPIO_SYSFS=n
- Una riga bianca seguita da una descrizione dettagliata della patch.
Questa descrizione può essere lunga tanto quanto serve; dovrebbe spiegare
cosa fa e perché dovrebbe essere aggiunta al kernel.
- Una o più righe etichette, con, minimo, una riga *Signed-off-by:*
col nome dall'autore della patch. Queste etichette verranno descritte
meglio più avanti.
Gli elementi qui sopra, assieme, formano il changelog di una patch.
Scrivere un buon changelog è cruciale ma è spesso un'arte trascurata;
vale la pena spendere qualche parola in più al riguardo. Quando scrivete
un changelog dovreste tenere ben presente che molte persone leggeranno
le vostre parole. Queste includono i manutentori di un sotto-sistema, e i
revisori che devono decidere se la patch debba essere inclusa o no,
le distribuzioni e altri manutentori che cercano di valutare se la patch
debba essere applicata su kernel più vecchi, i cacciatori di bachi che si
chiederanno se la patch è la causa di un problema che stanno cercando,
gli utenti che vogliono sapere com'è cambiato il kernel, e molti altri.
Un buon changelog fornisce le informazioni necessarie a tutte queste
persone nel modo più diretto e conciso possibile.
A questo scopo, la riga riassuntiva dovrebbe descrivere gli effetti della
modifica e la motivazione della patch nel modo migliore possibile nonostante
il limite di una sola riga. La descrizione dettagliata può spiegare meglio
i temi e fornire maggiori informazioni. Se una patch corregge un baco,
citate, se possibile, il commit che lo introdusse (e per favore, quando
citate un commit aggiungete sia il suo identificativo che il titolo),
Se il problema è associabile ad un file di log o all' output del compilatore,
includeteli al fine d'aiutare gli altri a trovare soluzioni per lo stesso
problema. Se la modifica ha lo scopo di essere di supporto a sviluppi
successivi, ditelo. Se le API interne vengono cambiate, dettagliate queste
modifiche e come gli altri dovrebbero agire per applicarle. In generale,
più riuscirete ad entrare nei panni di tutti quelli che leggeranno il
vostro changelog, meglio sarà il changelog (e il kernel nel suo insieme).
Non serve dirlo, un changelog dovrebbe essere il testo usato nel messaggio
di commit in un sistema di controllo di versione. Sarà seguito da:
- La patch stessa, nel formato unificato per patch ("-u"). Usare
l'opzione "-p" assocerà alla modifica il nome della funzione alla quale
si riferisce, rendendo il risultato più facile da leggere per gli altri.
Dovreste evitare di includere nelle patch delle modifiche per file
irrilevanti (quelli generati dal processo di generazione, per esempio, o i file
di backup del vostro editor). Il file "dontdiff" nella cartella Documentation
potrà esservi d'aiuto su questo punto; passatelo a diff con l'opzione "-X".
Le etichette sopra menzionante sono usate per descrivere come i vari
sviluppatori sono stati associati allo sviluppo di una patch. Sono descritte
in dettaglio nel documento :ref:`translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`;
quello che segue è un breve riassunto. Ognuna di queste righe ha il seguente
formato:
::
tag: Full Name <email address> optional-other-stuff
Le etichette in uso più comuni sono:
- Signed-off-by: questa è la certificazione che lo sviluppatore ha il diritto
di sottomettere la patch per l'integrazione nel kernel. Questo rappresenta
il consenso verso il certificato d'origine degli sviluppatori, il testo
completo potrà essere trovato in
:ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`.
Codice che non presenta una firma appropriata non potrà essere integrato.
- Co-developed-by: indica che la patch è stata sviluppata anche da un altro
sviluppatore assieme all'autore originale. Questo è utile quando più
persone lavorano sulla stessa patch. Da notare che questa persona deve
avere anche una riga "Signed-off-by:" nella patch.
- Acked-by: indica il consenso di un altro sviluppatore (spesso il manutentore
del codice in oggetto) all'integrazione della patch nel kernel.
- Tested-by: menziona la persona che ha verificato la patch e l'ha trovata
funzionante.
- Reviwed-by: menziona lo sviluppatore che ha revisionato la patch; per
maggiori dettagli leggete la dichiarazione dei revisori in
:ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`
- Reported-by: menziona l'utente che ha riportato il problema corretto da
questa patch; quest'etichetta viene usata per dare credito alle persone
che hanno verificato il codice e ci hanno fatto sapere quando le cose non
funzionavano correttamente.
- Cc: la persona menzionata ha ricevuto una copia della patch ed ha avuto
l'opportunità di commentarla.
State attenti ad aggiungere queste etichette alla vostra patch: solo
"Cc:" può essere aggiunta senza il permesso esplicito della persona menzionata.
Inviare la modifica
-------------------
Prima di inviare la vostra patch, ci sarebbero ancora un paio di cose di cui
dovreste aver cura:
- Siete sicuri che il vostro programma di posta non corromperà le patch?
Le patch che hanno spazi bianchi in libertà o andate a capo aggiunti
dai programmi di posta non funzioneranno per chi le riceve, e spesso
non verranno nemmeno esaminate in dettaglio. Se avete un qualsiasi dubbio,
inviate la patch a voi stessi e verificate che sia integra.
:ref:`Documentation/translations/it_IT/process/email-clients.rst <it_email_clients>`
contiene alcuni suggerimenti utili sulla configurazione dei programmi
di posta al fine di inviare patch.
- Siete sicuri che la vostra patch non contenga sciocchi errori? Dovreste
sempre processare le patch con scripts/checkpatch.pl e correggere eventuali
problemi riportati. Per favore tenete ben presente che checkpatch.pl non è
più intelligente di voi, nonostante sia il risultato di un certa quantità di
ragionamenti su come debba essere una patch per il kernel. Se seguire
i suggerimenti di checkpatch.pl rende il codice peggiore, allora non fatelo.
Le patch dovrebbero essere sempre inviate come testo puro. Per favore non
inviatele come allegati; questo rende molto più difficile, per i revisori,
citare parti della patch che si vogliono commentare. Invece, mettete la vostra
patch direttamente nel messaggio.
Quando inviate le patch, è importante inviarne una copia a tutte le persone che
potrebbero esserne interessate. Al contrario di altri progetti, il kernel
incoraggia le persone a peccare nell'invio di tante copie; non presumente che
le persone interessate vedano i vostri messaggi sulla lista di discussione.
In particolare le copie dovrebbero essere inviate a:
- I manutentori dei sottosistemi affetti della modifica. Come descritto
in precedenza, il file MAINTAINERS è il primo luogo dove cercare i nomi
di queste persone.
- Altri sviluppatori che hanno lavorato nello stesso ambiente - specialmente
quelli che potrebbero lavorarci proprio ora. Usate git potrebbe essere
utile per vedere chi altri ha modificato i file su cui state lavorando.
- Se state rispondendo a un rapporto su un baco, o a una richiesta di
funzionalità, includete anche gli autori di quei rapporti/richieste.
- Inviate una copia alle liste di discussione interessate, o, se nient'altro
è adatto, alla lista linux-kernel
- Se state correggendo un baco, pensate se la patch dovrebbe essere inclusa
nel prossimo rilascio stabile. Se è così, la lista di discussione
stable@vger.kernel.org dovrebbe riceverne una copia. Aggiungete anche
l'etichetta "Cc: stable@vger.kernel.org" nella patch stessa; questo
permetterà alla squadra *stable* di ricevere una notifica quando questa
correzione viene integrata nel ramo principale.
Quando scegliete i destinatari della patch, è bene avere un'idea di chi
pensiate che sia colui che, eventualmente, accetterà la vostra patch e
la integrerà. Nonostante sia possibile inviare patch direttamente a
Linus Torvalds, e lasciare che sia lui ad integrarle,solitamente non è la
strada migliore da seguire. Linus è occupato, e ci sono dei manutentori di
sotto-sistema che controllano una parte specifica del kernel. Solitamente,
vorreste che siano questi manutentori ad integrare le vostre patch. Se non
c'è un chiaro manutentore, l'ultima spiaggia è spesso Andrew Morton.
Le patch devono avere anche un buon oggetto. Il tipico formato per l'oggetto
di una patch assomiglia a questo:
::
[PATCH nn/mm] subsys: one-line description of the patch
dove "nn" è il numero ordinale della patch, "mm" è il numero totale delle patch
nella serie, e "subsys" è il nome del sottosistema interessato. Chiaramente,
nn/mm può essere omesso per una serie composta da una singola patch.
Se avete una significative serie di patch, è prassi inviare una descrizione
introduttiva come parte zero. Tuttavia questa convenzione non è universalmente
seguita; se la usate, ricordate che le informazioni nell'introduzione non
faranno parte del changelog del kernel. Quindi per favore, assicuratevi che
ogni patch abbia un changelog completo.
In generale, la seconda parte e quelle successive di una patch "composta"
dovrebbero essere inviate come risposta alla prima, cosicché vengano viste
come un unico *thread*. Strumenti come git e quilt hanno comandi per inviare
gruppi di patch con la struttura appropriata. Se avete una serie lunga
e state usando git, per favore state alla larga dall'opzione --chain-reply-to
per evitare di creare un annidamento eccessivo.
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/6.Followthrough.rst <development_followthrough>`
:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>
.. _it_development_followthrough:
=============
Completamento
=============
.. warning::
A questo punto, avete seguito le linee guida fino a questo punto e, con
l'aggiunta delle vostre capacità ingegneristiche, avete pubblicato una serie
perfetta di patch. Uno dei più grandi errori che possono essere commessi
persino da sviluppatori kernel esperti è quello di concludere che il
lavoro sia ormai finito. In verità, la pubblicazione delle patch
simboleggia una transizione alla fase successiva del processo, con,
probabilmente, ancora un po' di lavoro da fare.
È raro che una modifica sia così bella alla sua prima pubblicazione che non
ci sia alcuno spazio di miglioramento. Il programma di sviluppo del kernel
riconosce questo fatto e quindi, è fortemente orientato al miglioramento
del codice pubblicato. Voi, in qualità di autori del codice, dovrete
lavorare con la comunità del kernel per assicurare che il vostro codice
mantenga gli standard qualitativi richiesti. Un fallimento in questo
processo è quasi come impedire l'inclusione delle vostre patch nel
ramo principale.
Lavorare con i revisori
=======================
Una patch che abbia una certa rilevanza avrà ricevuto numerosi commenti
da parte di altri sviluppatori dato che avranno revisionato il codice.
Lavorare con i revisori può rivelarsi, per molti sviluppatori, la parte
più intimidatoria del processo di sviluppo del kernel. La vita può esservi
resa molto più facile se tenete presente alcuni dettagli:
- Se avete descritto la vostra modifica correttamente, i revisori ne
comprenderanno il valore e il perché vi siete presi il disturbo di
scriverla. Ma tale valore non li tratterrà dal porvi una domanda
fondamentale: come verrà mantenuto questo codice nel kernel nei prossimi
cinque o dieci anni? Molti dei cambiamenti che potrebbero esservi
richiesti - da piccoli problemi di stile a sostanziali ristesure -
vengono dalla consapevolezza che Linux resterà in circolazione e in
continuo sviluppo ancora per diverse decadi.
- La revisione del codice è un duro lavoro, ed è un mestiere poco
riconosciuto; le persone ricordano chi ha scritto il codice, ma meno
fama è attribuita a chi lo ha revisionato. Quindi i revisori potrebbero
divenire burberi, specialmente quando vendono i medesimi errori venire
fatti ancora e ancora. Se ricevete una revisione che vi sembra abbia
un tono arrabbiato, insultante o addirittura offensivo, resistente alla
tentazione di rispondere a tono. La revisione riguarda il codice e non
la persona, e i revisori non vi stanno attaccando personalmente.
- Similarmente, i revisori del codice non stanno cercando di promuovere
i loro interessi a vostre spese. Gli sviluppatori del kernel spesso si
aspettano di lavorare sul kernel per anni, ma sanno che il loro datore
di lavoro può cambiare. Davvero, senza praticamente eccezioni, loro
stanno lavorando per la creazione del miglior kernel possibile; non
stanno cercando di creare un disagio ad aziende concorrenti.
Quello che si sta cercando di dire è che, quando i revisori vi inviano degli
appunti dovete fare attenzione alle osservazioni tecniche che vi stanno
facendo. Non lasciate che il loro modo di esprimersi o il vostro orgoglio
impediscano che ciò accada. Quando avete dei suggerimenti sulla revisione,
prendetevi il tempo per comprendere cosa il revisore stia cercando di
comunicarvi. Se possibile, sistemate le cose che il revisore vi chiede di
modificare. E rispondete al revisore ringraziandolo e spiegando come
intendete fare.
Notate che non dovete per forza essere d'accordo con ogni singola modifica
suggerita dai revisori. Se credete che il revisore non abbia compreso
il vostro codice, spiegateglielo. Se avete un'obiezione tecnica da fargli
su di una modifica suggerita, spiegatela inserendo anche la vostra soluzione
al problema. Se la vostra spiegazione ha senso, il revisore la accetterà.
Tuttavia, la vostra motivazione potrebbe non essere del tutto persuasiva,
specialmente se altri iniziano ad essere d'accordo con il revisore.
Prendetevi quindi un po' di tempo per pensare ancora alla cosa. Può risultare
facile essere accecati dalla propria soluzione al punto che non realizzate che
c'è qualcosa di fondamentalmente sbagliato o, magari, non state nemmeno
risolvendo il problema giusto.
Andrew Morton suggerisce che ogni suggerimento di revisione che non è
presente nella modifica del codice dovrebbe essere inserito in un commento
aggiuntivo; ciò può essere d'aiuto ai futuri revisori nell'evitare domande
che sorgono al primo sguardo.
Un errore fatale è quello di ignorare i commenti di revisione nella speranza
che se ne andranno. Non andranno via. Se pubblicherete nuovamente il
codice senza aver risposto ai commenti ricevuti, probabilmente le vostre
modifiche non andranno da nessuna parte.
Parlando di ripubblicazione del codice: per favore tenete a mente che i
revisori non ricorderanno tutti i dettagli del codice che avete pubblicato
l'ultima volta. Quindi è sempre una buona idea quella di ricordare ai
revisori le questioni sollevate precedetemene e come le avete risolte.
I revisori non dovrebbero star lì a cercare all'interno degli archivi per
famigliarizzare con ciò che è stato detto l'ultima volta; se li aiutate
in questo senso, saranno di umore migliore quando riguarderanno il vostro
codice.
Se invece avete cercato di far tutto correttamente ma le cose continuano
a non andar bene? Molti disaccordi di natura tecnica possono essere risolti
attraverso la discussione, ma ci sono volte dove qualcuno deve prendere
una decisione. Se credete veramente che tale decisione andrà contro di voi
ingiustamente, potete sempre tentare di rivolgervi a qualcuno più
in alto di voi. Per cose di questo genere la persona con più potere è
Andrew Morton. Andrew è una figura molto rispettata all'interno della
comunità di sviluppo del kernel; lui può spesso sbrogliare situazioni che
sembrano irrimediabilmente bloccate. Rivolgersi ad Andrew non deve essere
fatto alla leggera, e non deve essere fatto prima di aver esplorato tutte
le altre alternative. E tenete a mente, ovviamente, che nemmeno lui
potrebbe non essere d'accordo con voi.
Cosa accade poi
===============
Se la modifica è ritenuta un elemento valido da essere aggiunta al kernel,
e una volta che la maggior parte degli appunti dei revisori sono stati
sistemati, il passo successivo solitamente è quello di entrare in un
sottosistema gestito da un manutentore. Come ciò avviene dipende dal
sottosistema medesimo; ogni manutentore ha il proprio modo di fare le cose.
In particolare, ci potrebbero essere diversi sorgenti - uno, magari, dedicato
alle modifiche pianificate per la finestra di fusione successiva, e un altro
per il lavoro di lungo periodo.
Per le modifiche proposte in aree per le quali non esiste un sottosistema
preciso (modifiche di gestione della memoria, per esempio), i sorgenti di
ripiego finiscono per essere -mm. Ed anche le modifiche che riguardano
più sottosistemi possono finire in quest'ultimo.
L'inclusione nei sorgenti di un sottosistema può comportare per una patch,
un alto livello di visibilità. Ora altri sviluppatori che stanno lavorando
in quei medesimi sorgenti avranno le vostre modifiche. I sottosistemi
solitamente riforniscono anche Linux-next, rendendo i propri contenuti
visibili all'intera comunità di sviluppo. A questo punto, ci sono buone
possibilità per voi di ricevere ulteriori commenti da un nuovo gruppo di
revisori; anche a questi commenti dovrete rispondere come avete già fatto per
gli altri.
Ciò che potrebbe accadere a questo punto, in base alla natura della vostra
modifica, riguarda eventuali conflitti con il lavoro svolto da altri.
Nella peggiore delle situazioni, i conflitti più pesanti tra modifiche possono
concludersi con la messa a lato di alcuni dei lavori svolti cosicché le
modifiche restanti possano funzionare ed essere integrate. Altre volte, la
risoluzione dei conflitti richiederà del lavoro con altri sviluppatori e,
possibilmente, lo spostamento di alcune patch da dei sorgenti a degli altri
in modo da assicurare che tutto sia applicato in modo pulito. Questo lavoro
può rivelarsi una spina nel fianco, ma consideratevi fortunati: prima
dell'avvento dei sorgenti linux-next, questi conflitti spesso emergevano solo
durante l'apertura della finestra di integrazione e dovevano essere smaltiti
in fretta. Ora essi possono essere risolti comodamente, prima dell'apertura
della finestra.
Un giorno, se tutto va bene, vi collegherete e vedrete che la vostra patch
è stata inserita nel ramo principale de kernel. Congratulazioni! Terminati
i festeggiamenti (nel frattempo avrete inserito il vostro nome nel file
MAINTAINERS) vale la pena ricordare una piccola cosa, ma importante: il
lavoro non è ancora finito. L'inserimento nel ramo principale porta con se
nuove sfide.
Cominciamo con il dire che ora la visibilità della vostra modifica è
ulteriormente cresciuta. Ci potrebbe portare ad una nuova fase di
commenti dagli sviluppatori che non erano ancora a conoscenza della vostra
patch. Ignorarli potrebbe essere allettante dato che non ci sono più
dubbi sull'integrazione della modifica. Resistete a tale tentazione, dovete
mantenervi disponibili agli sviluppatori che hanno domande o suggerimenti
per voi.
Ancora più importante: l'inclusione nel ramo principale mette il vostro
codice nelle mani di un gruppo di *tester* molto più esteso. Anche se avete
contribuito ad un driver per un hardware che non è ancora disponibile, sarete
sorpresi da quante persone inseriranno il vostro codice nei loro kernel.
E, ovviamente, dove ci sono *tester*, ci saranno anche dei rapporti su
eventuali bachi.
La peggior specie di rapporti sono quelli che indicano delle regressioni.
Se la vostra modifica causa una regressione, avrete un gran numero di
occhi puntati su di voi; la regressione deve essere sistemata il prima
possibile. Se non vorrete o non sarete capaci di sistemarla (e nessuno
lo farà per voi), la vostra modifica sarà quasi certamente rimossa durante
la fase di stabilizzazione. Oltre alla perdita di tutto il lavoro svolto
per far si che la vostra modifica fosse inserita nel ramo principale,
l'avere una modifica rimossa a causa del fallimento nel sistemare una
regressione, potrebbe rendere più difficile per voi far accettare
il vostro lavoro in futuro.
Dopo che ogni regressione è stata affrontata, ci potrebbero essere altri
bachi ordinari da "sconfiggere". Il periodo di stabilizzazione è la
vostra migliore opportunità per sistemare questi bachi e assicurarvi che
il debutto del vostro codice nel ramo principale del kernel sia il più solido
possibile. Quindi, per favore, rispondete ai rapporti sui bachi e ponete
rimedio, se possibile, a tutti i problemi. È a questo che serve il periodo
di stabilizzazione; potete iniziare creando nuove fantastiche modifiche
una volta che ogni problema con le vecchie sia stato risolto.
Non dimenticate che esistono altre pietre miliari che possono generare
rapporti sui bachi: il successivo rilascio stabile, quando una distribuzione
importante usa una versione del kernel nel quale è presente la vostra
modifica, eccetera. Il continuare a rispondere a questi rapporti è fonte di
orgoglio per il vostro lavoro. Se questa non è una sufficiente motivazione,
allora, è anche consigliabile considera che la comunità di sviluppo ricorda
gli sviluppatori che hanno perso interesse per il loro codice una volta
integrato. La prossima volta che pubblicherete una patch, la comunità
la valuterà anche sulla base del fatto che non sarete disponibili a
prendervene cura anche nel futuro.
Altre cose che posso accadere
=============================
Un giorno, potreste aprire la vostra email e vedere che qualcuno vi ha
inviato una patch per il vostro codice. Questo, dopo tutto, è uno dei
vantaggi di avere il vostro codice "là fuori". Se siete d'accordo con
la modifica, potrete anche inoltrarla ad un manutentore di sottosistema
(assicuratevi di includere la riga "From:" cosicché l'attribuzione sia
corretta, e aggiungete una vostra firma "Signed-off-by"), oppure inviate
un "Acked-by:" e lasciate che l'autore originale la invii.
Se non siete d'accordo con la patch, inviate una risposta educata
spiegando il perché. Se possibile, dite all'autore quali cambiamenti
servirebbero per rendere la patch accettabile da voi. C'è una certa
riluttanza nell'inserire modifiche con un conflitto fra autore
e manutentore del codice, ma solo fino ad un certo punto. Se siete visti
come qualcuno che blocca un buon lavoro senza motivo, quelle patch vi
passeranno oltre e andranno nel ramo principale in ogni caso. Nel kernel
Linux, nessuno ha potere di veto assoluto su alcun codice. Eccezione
fatta per Linus, forse.
TODO ancora da tradurre
In rarissime occasioni, potreste vedere qualcosa di completamente diverso:
un altro sviluppatore che pubblica una soluzione differente al vostro
problema. A questo punto, c'è una buona probabilità che una delle due
modifiche non verrà integrata, e il "c'ero prima io" non è considerato
un argomento tecnico rilevante. Se la modifica di qualcun'altro rimpiazza
la vostra ed entra nel ramo principale, esiste un unico modo di reagire:
siate contenti che il vostro problema sia stato risolto e andate avanti con
il vostro lavoro. L'avere un vostro lavoro spintonato da parte in questo
modo può essere avvilente e scoraggiante, ma la comunità ricorderà come
avrete reagito anche dopo che avrà dimenticato quale fu la modifica accettata.
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/7.AdvancedTopics.rst <development_advancedtopics>`
:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
.. _it_development_advancedtopics:
Argomenti avanzati
==================
.. warning::
A questo punto, si spera, dovreste avere un'idea su come funziona il processo
di sviluppo. Ma rimane comunque molto da imparare! Questo capitolo copre
alcuni argomenti che potrebbero essere utili per gli sviluppatori che stanno
per diventare parte integrante del processo di sviluppo del kernel.
Gestire le modifiche con git
-----------------------------
L'uso di un sistema distribuito per il controllo delle versioni del kernel
ebbe iniziò nel 2002 quando Linux iniziò a provare il programma proprietario
BitKeeper. Nonostante l'uso di BitKeeper fosse opinabile, di certo il suo
approccio alla gestione dei sorgenti non lo era. Un sistema distribuito per
il controllo delle versioni accelerò immediatamente lo sviluppo del kernel.
Oggigiorno, ci sono diverse alternative libere a BitKeeper. Per il meglio o il
peggio, il progetto del kernel ha deciso di usare git per gestire i sorgenti.
Gestire le modifiche con git può rendere la vita dello sviluppatore molto
più facile, specialmente quando il volume delle modifiche cresce.
Git ha anche i suoi lati taglienti che possono essere pericolosi; è uno
strumento giovane e potente che è ancora in fase di civilizzazione da parte
dei suoi sviluppatori. Questo documento non ha lo scopo di insegnare l'uso
di git ai suoi lettori; ci sarebbe materiale a sufficienza per un lungo
documento al riguardo. Invece, qui ci concentriamo in particolare su come
git è parte del processo di sviluppo del kernel. Gli sviluppatori che
desiderassero diventare agili con git troveranno più informazioni ai
seguenti indirizzi:
http://git-scm.com/
http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
e su varie guide che potrete trovare su internet.
La prima cosa da fare prima di usarlo per produrre patch che saranno
disponibili ad altri, è quella di leggere i siti qui sopra e di acquisire una
base solida su come funziona git. Uno sviluppatore che sappia usare git
dovrebbe essere capace di ottenere una copia del repositorio principale,
esplorare la storia della revisione, registrare le modifiche, usare i rami,
eccetera. Una certa comprensione degli strumenti git per riscrivere la storia
(come ``rebase``) è altrettanto utile. Git ha i propri concetti e la propria
terminologia; un nuovo utente dovrebbe conoscere *refs*, *remote branch*,
*index*, *fast-forward merge*, *push* e *pull*, *detached head*, eccetera.
Il tutto potrebbe essere un po' intimidatorio visto da fuori, ma con un po'
di studio i concetti non saranno così difficili da capire.
Utilizzare git per produrre patch da sottomettere via email può essere
un buon esercizio da fare mentre si sta prendendo confidenza con lo strumento.
Quando sarete in grado di creare rami git che siano guardabili da altri,
vi servirà, ovviamente, un server dal quale sia possibile attingere le vostre
modifiche. Se avete un server accessibile da Internet, configurarlo per
eseguire git-daemon è relativamente semplice . Altrimenti, iniziano a
svilupparsi piattaforme che offrono spazi pubblici, e gratuiti (Github,
per esempio). Gli sviluppatori permanenti possono ottenere un account
su kernel.org, ma non è proprio facile da ottenere; per maggiori informazioni
consultate la pagina web http://kernel.org/faq/.
In git è normale avere a che fare con tanti rami. Ogni linea di sviluppo
può essere separata in "rami per argomenti" e gestiti indipendentemente.
In git i rami sono facilissimi, per cui non c'è motivo per non usarli
in libertà. In ogni caso, non dovreste sviluppare su alcun ramo dal
quale altri potrebbero attingere. I rami disponibili pubblicamente dovrebbero
essere creati con attenzione; integrate patch dai rami di sviluppo
solo quando sono complete e pronte ad essere consegnate - non prima.
Git offre alcuni strumenti che vi permettono di riscrivere la storia del
vostro sviluppo. Una modifica errata (diciamo, una che rompe la bisezione,
oppure che ha un qualche tipo di baco evidente) può essere corretta sul posto
o fatta sparire completamente dalla storia. Una serie di patch può essere
riscritta come se fosse stata scritta in cima al ramo principale di oggi,
anche se ci avete lavorato per mesi. Le modifiche possono essere spostate
in modo trasparente da un ramo ad un altro. E così via. Un uso giudizioso
di git per revisionare la storia può aiutare nella creazione di una serie
di patch pulite e con meno problemi.
Un uso eccessivo può portare ad altri tipi di problemi, tuttavia, oltre
alla semplice ossessione per la creazione di una storia del progetto che sia
perfetta. Riscrivere la storia riscriverà le patch contenute in quella
storia, trasformando un kernel verificato (si spera) in uno da verificare.
Ma, oltre a questo, gli sviluppatori non possono collaborare se non condividono
la stessa vista sulla storia del progetto; se riscrivete la storia dalla quale
altri sviluppatori hanno attinto per i loro repositori, renderete la loro vita
molto più difficile. Quindi tenete conto di questa semplice regola generale:
la storia che avete esposto ad altri, generalmente, dovrebbe essere vista come
immutabile.
Dunque, una volta che il vostro insieme di patch è stato reso disponibile
pubblicamente non dovrebbe essere più sovrascritto. Git tenterà di imporre
questa regola, e si rifiuterà di pubblicare nuove patch che non risultino
essere dirette discendenti di quelle pubblicate in precedenza (in altre parole,
patch che non condividono la stessa storia). È possibile ignorare questo
controllo, e ci saranno momenti in cui sarà davvero necessario riscrivere
un ramo già pubblicato. Un esempio è linux-next dove le patch vengono
spostate da un ramo all'altro al fine di evitare conflitti. Ma questo tipo
d'azione dovrebbe essere un'eccezione. Questo è uno dei motivi per cui lo
sviluppo dovrebbe avvenire in rami privati (che possono essere sovrascritti
quando lo si ritiene necessario) e reso pubblico solo quando è in uno stato
avanzato.
Man mano che il ramo principale (o altri rami su cui avete basato le
modifiche) avanza, diventa allettante l'idea di integrare tutte le patch
per rimanere sempre aggiornati. Per un ramo privato, il *rebase* può essere
un modo semplice per rimanere aggiornati, ma questa non è un'opzione nel
momento in cui il vostro ramo è stato esposto al mondo intero.
*Merge* occasionali possono essere considerati di buon senso, ma quando
diventano troppo frequenti confondono inutilmente la storia. La tecnica
suggerita in questi casi è quella di fare *merge* raramente, e più in generale
solo nei momenti di rilascio (per esempio gli -rc del ramo principale).
Se siete nervosi circa alcune patch in particolare, potete sempre fare
dei *merge* di test in un ramo privato. In queste situazioni git "rerere"
può essere utile; questo strumento si ricorda come i conflitti di *merge*
furono risolti in passato cosicché non dovrete fare lo stesso lavoro due volte.
Una delle lamentele più grosse e ricorrenti sull'uso di strumenti come git
è il grande movimento di patch da un repositorio all'altro che rende
facile l'integrazione nel ramo principale di modifiche mediocri, il tutto
sotto il naso dei revisori. Gli sviluppatori del kernel tendono ad essere
scontenti quando vedono succedere queste cose; preparare un ramo git con
patch che non hanno ricevuto alcuna revisione o completamente avulse, potrebbe
influire sulla vostra capacita di proporre, in futuro, l'integrazione dei
vostri rami. Citando Linus
::
Potete inviarmi le vostre patch, ma per far si che io integri una
vostra modifica da git, devo sapere che voi sappiate cosa state
facendo, e ho bisogno di fidarmi *senza* dover passare tutte
le modifiche manualmente una per una.
(http://lwn.net/Articles/224135/).
Per evitare queste situazioni, assicuratevi che tutte le patch in un ramo
siano strettamente correlate al tema delle modifiche; un ramo "driver fixes"
non dovrebbe fare modifiche al codice principale per la gestione della memoria.
E, più importante ancora, non usate un repositorio git per tentare di
evitare il processo di revisione. Pubblicate un sommario di quello che il
vostro ramo contiene sulle liste di discussione più opportune, e , quando
sarà il momento, richiedete che il vostro ramo venga integrato in linux-next.
Se e quando altri inizieranno ad inviarvi patch per essere incluse nel
vostro repositorio, non dovete dimenticare di revisionarle. Inoltre
assicuratevi di mantenerne le informazioni di paternità; al riguardo git "am"
fa del suo meglio, ma potreste dover aggiungere una riga "From:" alla patch
nel caso in cui sia arrivata per vie traverse.
Quando richiedete l'integrazione, siate certi di fornire tutte le informazioni:
dov'è il vostro repositorio, quale ramo integrare, e quali cambiamenti si
otterranno dall'integrazione. Il comando git request-pull può essere d'aiuto;
preparerà una richiesta nel modo in cui gli altri sviluppatori se l'aspettano,
e verificherà che vi siate ricordati di pubblicare quelle patch su un
server pubblico.
Revisionare le patch
--------------------
Alcuni lettori potrebbero avere obiezioni sulla presenza di questa sezione
negli "argomenti avanzati" sulla base che anche gli sviluppatori principianti
dovrebbero revisionare le patch. É certamente vero che non c'è modo
migliore di imparare come programmare per il kernel che guardare il codice
pubblicato dagli altri. In aggiunta, i revisori sono sempre troppo pochi;
guardando il codice potete apportare un significativo contributo all'intero
processo.
Revisionare il codice potrebbe risultare intimidatorio, specialmente per i
nuovi arrivati che potrebbero sentirsi un po' nervosi nel questionare
il codice - in pubblico - pubblicato da sviluppatori più esperti. Perfino
il codice scritto dagli sviluppatori più esperti può essere migliorato.
Forse il suggerimento migliore per i revisori (tutti) è questo: formulate
i commenti come domande e non come critiche. Chiedere "Come viene rilasciato
il *lock* in questo percorso?" funziona sempre molto meglio che
"qui la sincronizzazione è sbagliata".
TODO ancora da tradurre
Diversi sviluppatori revisioneranno il codice con diversi punti di vista.
Alcuni potrebbero concentrarsi principalmente sullo stile del codice e se
alcune linee hanno degli spazio bianchi di troppo. Altri si chiederanno
se accettare una modifica interamente è una cosa positiva per il kernel
o no. E altri ancora si focalizzeranno sui problemi di sincronizzazione,
l'uso eccessivo di *stack*, problemi di sicurezza, duplicazione del codice
in altri contesti, documentazione, effetti negativi sulle prestazioni, cambi
all'ABI dello spazio utente, eccetera. Qualunque tipo di revisione è ben
accetta e di valore, se porta ad avere un codice migliore nel kernel.
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/8.Conclusion.rst <development_conclusion>`
:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>
.. _it_development_conclusion:
Per maggiori informazioni
=========================
.. warning::
Esistono numerose fonti di informazioni sullo sviluppo del kernel Linux
e argomenti correlati. Primo tra questi sarà sempre la cartella Documentation
che si trova nei sorgenti kernel.
TODO ancora da tradurre
Il file :ref:`process/howto.rst <it_process_howto>` è un punto di partenza
importante; :ref:`process/submitting-patches.rst <it_submittingpatches>` e
:ref:`process/submitting-drivers.rst <it_submittingdrivers>` sono
anch'essi qualcosa che tutti gli sviluppatori del kernel dovrebbero leggere.
Molte API interne al kernel sono documentate utilizzando il meccanismo
kerneldoc; "make htmldocs" o "make pdfdocs" possono essere usati per generare
quei documenti in HTML o PDF (sebbene le versioni di TeX di alcune
distribuzioni hanno dei limiti interni e fallisce nel processare
appropriatamente i documenti).
Diversi siti web approfondiscono lo sviluppo del kernel ad ogni livello
di dettaglio. Il vostro autore vorrebbe umilmente suggerirvi
http://lwn.net/ come fonte; usando l'indice 'kernel' su LWN troverete
molti argomenti specifici sul kernel:
http://lwn.net/Kernel/Index/
Oltre a ciò, una risorsa valida per gli sviluppatori kernel è:
http://kernelnewbies.org/
E, ovviamente, una fonte da non dimenticare è http://kernel.org/, il luogo
definitivo per le informazioni sui rilasci del kernel.
Ci sono numerosi libri sullo sviluppo del kernel:
Linux Device Drivers, 3rd Edition (Jonathan Corbet, Alessandro
Rubini, and Greg Kroah-Hartman). In linea all'indirizzo
http://lwn.net/Kernel/LDD3/.
Linux Kernel Development (Robert Love).
Understanding the Linux Kernel (Daniel Bovet and Marco Cesati).
Tutti questi libri soffrono di un errore comune: tendono a risultare in un
certo senso obsoleti dal momento che si trovano in libreria da diverso
tempo. Comunque contengono informazioni abbastanza buone.
La documentazione per git la troverete su:
http://www.kernel.org/pub/software/scm/git/docs/
http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
Conclusioni
===========
Congratulazioni a chiunque ce l'abbia fatta a terminare questo documento di
lungo-respiro. Si spera che abbia fornito un'utile comprensione d'insieme
di come il kernel Linux viene sviluppato e di come potete partecipare a
tale processo.
Infine, quello che conta è partecipare. Qualsiasi progetto software
open-source non è altro che la somma di quello che i suoi contributori
mettono al suo interno. Il kernel Linux è cresciuto velocemente e bene
perché ha ricevuto il supporto di un impressionante gruppo di sviluppatori,
ognuno dei quali sta lavorando per renderlo migliore. Il kernel è un esempio
importante di cosa può essere fatto quando migliaia di persone lavorano
insieme verso un obiettivo comune.
Il kernel può sempre beneficiare di una larga base di sviluppatori, tuttavia,
c'è sempre molto lavoro da fare. Ma, cosa non meno importante, molti degli
altri partecipanti all'ecosistema Linux possono trarre beneficio attraverso
il contributo al kernel. Inserire codice nel ramo principale è la chiave
per arrivare ad una qualità del codice più alta, bassa manutenzione e
bassi prezzi di distribuzione, alti livelli d'influenza sulla direzione
dello sviluppo del kernel, e molto altro. È una situazione nella quale
tutti coloro che sono coinvolti vincono. Mollate il vostro editor e
raggiungeteci; sarete più che benvenuti.
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/adding-syscalls.rst <addsyscalls>`
:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
.. _it_addsyscalls:
Aggiungere una nuova chiamata di sistema
========================================
.. warning::
Questo documento descrive quello che è necessario sapere per aggiungere
nuove chiamate di sistema al kernel Linux; questo è da considerarsi come
un'aggiunta ai soliti consigli su come proporre nuove modifiche
:ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`.
TODO ancora da tradurre
Alternative alle chiamate di sistema
------------------------------------
La prima considerazione da fare quando si aggiunge una nuova chiamata di
sistema è quella di valutare le alternative. Nonostante le chiamate di sistema
siano il punto di interazione fra spazio utente e kernel più tradizionale ed
ovvio, esistono altre possibilità - scegliete quella che meglio si adatta alle
vostra interfaccia.
- Se le operazioni coinvolte possono rassomigliare a quelle di un filesystem,
allora potrebbe avere molto più senso la creazione di un nuovo filesystem o
dispositivo. Inoltre, questo rende più facile incapsulare la nuova
funzionalità in un modulo kernel piuttosto che essere sviluppata nel cuore
del kernel.
- Se la nuova funzionalità prevede operazioni dove il kernel notifica
lo spazio utente su un avvenimento, allora restituire un descrittore
di file all'oggetto corrispondente permette allo spazio utente di
utilizzare ``poll``/``select``/``epoll`` per ricevere quelle notifiche.
- Tuttavia, le operazioni che non si sposano bene con operazioni tipo
:manpage:`read(2)`/:manpage:`write(2)` dovrebbero essere implementate
come chiamate :manpage:`ioctl(2)`, il che potrebbe portare ad un'API in
un qualche modo opaca.
- Se dovete esporre solo delle informazioni sul sistema, un nuovo nodo in
sysfs (vedere ``Documentation/translations/it_IT/filesystems/sysfs.txt``) o
in procfs potrebbe essere sufficiente. Tuttavia, l'accesso a questi
meccanismi richiede che il filesystem sia montato, il che potrebbe non
essere sempre vero (per esempio, in ambienti come namespace/sandbox/chroot).
Evitate d'aggiungere nuove API in debugfs perché questo non viene
considerata un'interfaccia di 'produzione' verso lo spazio utente.
- Se l'operazione è specifica ad un particolare file o descrittore, allora
potrebbe essere appropriata l'aggiunta di un comando :manpage:`fcntl(2)`.
Tuttavia, :manpage:`fcntl(2)` è una chiamata di sistema multiplatrice che
nasconde una notevole complessità, quindi è ottima solo quando la nuova
funzione assomiglia a quelle già esistenti in :manpage:`fcntl(2)`, oppure
la nuova funzionalità è veramente semplice (per esempio, leggere/scrivere
un semplice flag associato ad un descrittore di file).
- Se l'operazione è specifica ad un particolare processo, allora
potrebbe essere appropriata l'aggiunta di un comando :manpage:`prctl(2)`.
Come per :manpage:`fcntl(2)`, questa chiamata di sistema è un complesso
multiplatore quindi è meglio usarlo per cose molto simili a quelle esistenti
nel comando ``prctl`` oppure per leggere/scrivere un semplice flag relativo
al processo.
Progettare l'API: pianificare le estensioni
-------------------------------------------
Una nuova chiamata di sistema diventerà parte dell'API del kernel, e
dev'essere supportata per un periodo indefinito. Per questo, è davvero
un'ottima idea quella di discutere apertamente l'interfaccia sulla lista
di discussione del kernel, ed è altrettanto importante pianificarne eventuali
estensioni future.
(Nella tabella delle chiamate di sistema sono disseminati esempi dove questo
non fu fatto, assieme ai corrispondenti aggiornamenti -
``eventfd``/``eventfd2``, ``dup2``/``dup3``, ``inotify_init``/``inotify_init1``,
``pipe``/``pipe2``, ``renameat``/``renameat2`` --quindi imparate dalla storia
del kernel e pianificate le estensioni fin dall'inizio)
Per semplici chiamate di sistema che accettano solo un paio di argomenti,
il modo migliore di permettere l'estensibilità è quello di includere un
argomento *flags* alla chiamata di sistema. Per assicurarsi che i programmi
dello spazio utente possano usare in sicurezza *flags* con diverse versioni
del kernel, verificate se *flags* contiene un qualsiasi valore sconosciuto,
in qual caso rifiutate la chiamata di sistema (con ``EINVAL``)::
if (flags & ~(THING_FLAG1 | THING_FLAG2 | THING_FLAG3))
return -EINVAL;
(Se *flags* non viene ancora utilizzato, verificate che l'argomento sia zero)
Per chiamate di sistema più sofisticate che coinvolgono un numero più grande di
argomenti, il modo migliore è quello di incapsularne la maggior parte in una
struttura dati che verrà passata per puntatore. Questa struttura potrà
funzionare con future estensioni includendo un campo *size*::
struct xyzzy_params {
u32 size; /* userspace sets p->size = sizeof(struct xyzzy_params) */
u32 param_1;
u64 param_2;
u64 param_3;
};
Fintanto che un qualsiasi campo nuovo, diciamo ``param_4``, è progettato per
offrire il comportamento precedente quando vale zero, allora questo permetterà
di gestire un conflitto di versione in entrambe le direzioni:
- un vecchio kernel può gestire l'accesso di una versione moderna di un
programma in spazio utente verificando che la memoria oltre la dimensione
della struttura dati attesa sia zero (in pratica verificare che
``param_4 == 0``).
- un nuovo kernel può gestire l'accesso di una versione vecchia di un
programma in spazio utente estendendo la struttura dati con zeri (in pratica
``param_4 = 0``).
Vedere :manpage:`perf_event_open(2)` e la funzione ``perf_copy_attr()`` (in
``kernel/events/core.c``) per un esempio pratico di questo approccio.
Progettare l'API: altre considerazioni
--------------------------------------
Se la vostra nuova chiamata di sistema permette allo spazio utente di fare
riferimento ad un oggetto del kernel, allora questa dovrebbe usare un
descrittore di file per accesso all'oggetto - non inventatevi nuovi tipi di
accesso da spazio utente quando il kernel ha già dei meccanismi e una semantica
ben definita per utilizzare i descrittori di file.
Se la vostra nuova chiamata di sistema :manpage:`xyzzy(2)` ritorna un nuovo
descrittore di file, allora l'argomento *flags* dovrebbe includere un valore
equivalente a ``O_CLOEXEC`` per i nuovi descrittori. Questo rende possibile,
nello spazio utente, la chiusura della finestra temporale fra le chiamate a
``xyzzy()`` e ``fcntl(fd, F_SETFD, FD_CLOEXEC)``, dove un inaspettato
``fork()`` o ``execve()`` potrebbe trasferire il descrittore al programma
eseguito (Comunque, resistete alla tentazione di riutilizzare il valore di
``O_CLOEXEC`` dato che è specifico dell'architettura e fa parte di una
enumerazione di flag ``O_*`` che è abbastanza ricca).
Se la vostra nuova chiamata di sistema ritorna un nuovo descrittore di file,
dovreste considerare che significato avrà l'uso delle chiamate di sistema
della famiglia di :manpage:`poll(2)`. Rendere un descrittore di file pronto
per la lettura o la scrittura è il tipico modo del kernel per notificare lo
spazio utente circa un evento associato all'oggetto del kernel.
Se la vostra nuova chiamata di sistema :manpage:`xyzzy(2)` ha un argomento
che è il percorso ad un file::
int sys_xyzzy(const char __user *path, ..., unsigned int flags);
dovreste anche considerare se non sia più appropriata una versione
:manpage:`xyzzyat(2)`::
int sys_xyzzyat(int dfd, const char __user *path, ..., unsigned int flags);
Questo permette più flessibilità su come lo spazio utente specificherà il file
in questione; in particolare, permette allo spazio utente di richiedere la
funzionalità su un descrittore di file già aperto utilizzando il *flag*
``AT_EMPTY_PATH``, in pratica otterremmo gratuitamente l'operazione
:manpage:`fxyzzy(3)`::
- xyzzyat(AT_FDCWD, path, ..., 0) is equivalent to xyzzy(path,...)
- xyzzyat(fd, "", ..., AT_EMPTY_PATH) is equivalent to fxyzzy(fd, ...)
(Per maggiori dettagli sulla logica delle chiamate \*at(), leggete la pagina
man :manpage:`openat(2)`; per un esempio di AT_EMPTY_PATH, leggere la pagina
man :manpage:`fstatat(2)`).
Se la vostra nuova chiamata di sistema :manpage:`xyzzy(2)` prevede un parametro
per descrivere uno scostamento all'interno di un file, usate ``loff_t`` come
tipo cosicché scostamenti a 64-bit potranno essere supportati anche su
architetture a 32-bit.
Se la vostra nuova chiamata di sistema :manpage:`xyzzy(2)` prevede l'uso di
funzioni riservate, allora dev'essere gestita da un opportuno bit di privilegio
(verificato con una chiamata a ``capable()``), come descritto nella pagina man
:manpage:`capabilities(7)`. Scegliete un bit di privilegio già esistente per
gestire la funzionalità associata, ma evitate la combinazione di diverse
funzionalità vagamente collegate dietro lo stesso bit, in quanto va contro il
principio di *capabilities* di separare i poteri di root. In particolare,
evitate di aggiungere nuovi usi al fin-troppo-generico privilegio
``CAP_SYS_ADMIN``.
Se la vostra nuova chiamata di sistema :manpage:`xyzzy(2)` manipola altri
processi oltre a quello chiamato, allora dovrebbe essere limitata (usando
la chiamata ``ptrace_may_access()``) di modo che solo un processo chiamante
con gli stessi permessi del processo in oggetto, o con i necessari privilegi,
possa manipolarlo.
Infine, state attenti che in alcune architetture non-x86 la vita delle chiamate
di sistema con argomenti a 64-bit viene semplificata se questi argomenti
ricadono in posizioni dispari (pratica, i parametri 1, 3, 5); questo permette
l'uso di coppie contigue di registri a 32-bit. (Questo non conta se gli
argomenti sono parte di una struttura dati che viene passata per puntatore).
Proporre l'API
--------------
Al fine di rendere le nuove chiamate di sistema di facile revisione, è meglio
che dividiate le modifiche i pezzi separati. Questi dovrebbero includere
almeno le seguenti voci in *commit* distinti (ognuno dei quali sarà descritto
più avanti):
- l'essenza dell'implementazione della chiamata di sistema, con i prototipi,
i numeri generici, le modifiche al Kconfig e l'implementazione *stub* di
ripiego.
- preparare la nuova chiamata di sistema per un'architettura specifica,
solitamente x86 (ovvero tutti: x86_64, x86_32 e x32).
- un programma di auto-verifica da mettere in ``tools/testing/selftests/``
che mostri l'uso della chiamata di sistema.
- una bozza di pagina man per la nuova chiamata di sistema. Può essere
scritta nell'email di presentazione, oppure come modifica vera e propria
al repositorio delle pagine man.
Le proposte di nuove chiamate di sistema, come ogni altro modifica all'API del
kernel, deve essere sottomessa alla lista di discussione
linux-api@vger.kernel.org.
Implementazione di chiamate di sistema generiche
------------------------------------------------
Il principale punto d'accesso alla vostra nuova chiamata di sistema
:manpage:`xyzzy(2)` verrà chiamato ``sys_xyzzy()``; ma, piuttosto che in modo
esplicito, lo aggiungerete tramite la macro ``SYSCALL_DEFINEn``. La 'n'
indica il numero di argomenti della chiamata di sistema; la macro ha come
argomento il nome della chiamata di sistema, seguito dalle coppie (tipo, nome)
per definire i suoi parametri. L'uso di questa macro permette di avere
i metadati della nuova chiamata di sistema disponibili anche per altri
strumenti.
Il nuovo punto d'accesso necessita anche del suo prototipo di funzione in
``include/linux/syscalls.h``, marcato come asmlinkage di modo da abbinargli
il modo in cui quelle chiamate di sistema verranno invocate::
asmlinkage long sys_xyzzy(...);
Alcune architetture (per esempio x86) hanno le loro specifiche tabelle di
chiamate di sistema (syscall), ma molte altre architetture condividono una
tabella comune di syscall. Aggiungete alla lista generica la vostra nuova
chiamata di sistema aggiungendo un nuovo elemento alla lista in
``include/uapi/asm-generic/unistd.h``::
#define __NR_xyzzy 292
__SYSCALL(__NR_xyzzy, sys_xyzzy)
Aggiornate anche il contatore __NR_syscalls di modo che sia coerente con
l'aggiunta della nuove chiamate di sistema; va notato che se più di una nuova
chiamata di sistema viene aggiunga nella stessa finestra di sviluppo, il numero
della vostra nuova syscall potrebbe essere aggiustato al fine di risolvere i
conflitti.
Il file ``kernel/sys_ni.c`` fornisce le implementazioni *stub* di ripiego che
ritornano ``-ENOSYS``. Aggiungete la vostra nuova chiamata di sistema anche
qui::
COND_SYSCALL(xyzzy);
La vostra nuova funzionalità del kernel, e la chiamata di sistema che la
controlla, dovrebbero essere opzionali. Quindi, aggiungete un'opzione
``CONFIG`` (solitamente in ``init/Kconfig``). Come al solito per le nuove
opzioni ``CONFIG``:
- Includete una descrizione della nuova funzionalità e della chiamata di
sistema che la controlla.
- Rendete l'opzione dipendente da EXPERT se dev'essere nascosta agli utenti
normali.
- Nel Makefile, rendere tutti i nuovi file sorgenti, che implementano la
nuova funzionalità, dipendenti dall'opzione CONFIG (per esempio
``obj-$(CONFIG_XYZZY_SYSCALL) += xyzzy.o``).
- Controllate due volte che sia possibile generare il kernel con la nuova
opzione CONFIG disabilitata.
Per riassumere, vi serve un *commit* che includa:
- un'opzione ``CONFIG``per la nuova funzione, normalmente in ``init/Kconfig``
- ``SYSCALL_DEFINEn(xyzzy, ...)`` per il punto d'accesso
- il corrispondente prototipo in ``include/linux/syscalls.h``
- un elemento nella tabella generica in ``include/uapi/asm-generic/unistd.h``
- *stub* di ripiego in ``kernel/sys_ni.c``
Implementazione delle chiamate di sistema x86
---------------------------------------------
Per collegare la vostra nuova chiamate di sistema alle piattaforme x86,
dovete aggiornate la tabella principale di syscall. Assumendo che la vostra
nuova chiamata di sistema non sia particolarmente speciale (vedere sotto),
dovete aggiungere un elemento *common* (per x86_64 e x32) in
arch/x86/entry/syscalls/syscall_64.tbl::
333 common xyzzy sys_xyzzy
e un elemento per *i386* ``arch/x86/entry/syscalls/syscall_32.tbl``::
380 i386 xyzzy sys_xyzzy
Ancora una volta, questi numeri potrebbero essere cambiati se generano
conflitti durante la finestra di integrazione.
Chiamate di sistema compatibili (generico)
------------------------------------------
Per molte chiamate di sistema, la stessa implementazione a 64-bit può essere
invocata anche quando il programma in spazio utente è a 32-bit; anche se la
chiamata di sistema include esplicitamente un puntatore, questo viene gestito
in modo trasparente.
Tuttavia, ci sono un paio di situazione dove diventa necessario avere un
livello di gestione della compatibilità per risolvere le differenze di
dimensioni fra 32-bit e 64-bit.
Il primo caso è quando un kernel a 64-bit supporta anche programmi in spazio
utente a 32-bit, perciò dovrà ispezionare aree della memoria (``__user``) che
potrebbero contenere valori a 32-bit o a 64-bit. In particolar modo, questo
è necessario quando un argomento di una chiamata di sistema è:
- un puntatore ad un puntatore
- un puntatore ad una struttura dati contenente a sua volta un puntatore
( ad esempio ``struct iovec __user *``)
- un puntatore ad un tipo intero di dimensione variabile (``time_t``,
``off_t``, ``long``, ...)
- un puntatore ad una struttura dati contenente un tipo intero di dimensione
variabile.
Il secondo caso che richiede un livello di gestione della compatibilità è
quando uno degli argomenti di una chiamata a sistema è esplicitamente un tipo
a 64-bit anche su architetture a 32-bit, per esempio ``loff_t`` o ``__u64``.
In questo caso, un valore che arriva ad un kernel a 64-bit da un'applicazione
a 32-bit verrà diviso in due valori a 32-bit che dovranno essere riassemblati
in questo livello di compatibilità.
(Da notare che non serve questo livello di compatibilità per argomenti che
sono puntatori ad un tipo esplicitamente a 64-bit; per esempio, in
:manpage:`splice(2)` l'argomento di tipo ``loff_t __user *`` non necessita
di una chiamata di sistema ``compat_``)
La versione compatibile della nostra chiamata di sistema si chiamerà
``compat_sys_xyzzy()``, e viene aggiunta utilizzando la macro
``COMPAT_SYSCALL_DEFINEn()`` (simile a SYSCALL_DEFINEn). Questa versione
dell'implementazione è parte del kernel a 64-bit ma accetta parametri a 32-bit
che trasformerà secondo le necessità (tipicamente, la versione
``compat_sys_`` converte questi valori nello loro corrispondente a 64-bit e
può chiamare la versione ``sys_`` oppure invocare una funzione che implementa
le parti comuni).
Il punto d'accesso *compat* deve avere il corrispondente prototipo di funzione
in ``include/linux/compat.h``, marcato come asmlinkage di modo da abbinargli
il modo in cui quelle chiamate di sistema verranno invocate::
asmlinkage long compat_sys_xyzzy(...);
Se la chiamata di sistema prevede una struttura dati organizzata in modo
diverso per sistemi a 32-bit e per quelli a 64-bit, diciamo
``struct xyzzy_args``, allora il file d'intestazione
``then the include/linux/compat.h`` deve includere la sua versione
*compatibile* (``struct compat_xyzzy_args``); ogni variabile con
dimensione variabile deve avere il proprio tipo ``compat_`` corrispondente
a quello in ``struct xyzzy_args``. La funzione ``compat_sys_xyzzy()``
può usare la struttura ``compat_`` per analizzare gli argomenti ricevuti
da una chiamata a 32-bit.
Per esempio, se avete i seguenti campi::
struct xyzzy_args {
const char __user *ptr;
__kernel_long_t varying_val;
u64 fixed_val;
/* ... */
};
nella struttura ``struct xyzzy_args``, allora la struttura
``struct compat_xyzzy_args`` dovrebbe avere::
struct compat_xyzzy_args {
compat_uptr_t ptr;
compat_long_t varying_val;
u64 fixed_val;
/* ... */
};
La lista generica delle chiamate di sistema ha bisogno di essere
aggiustata al fine di permettere l'uso della versione *compatibile*;
la voce in ``include/uapi/asm-generic/unistd.h`` dovrebbero usare
``__SC_COMP`` piuttosto di ``__SYSCALL``::
#define __NR_xyzzy 292
__SC_COMP(__NR_xyzzy, sys_xyzzy, compat_sys_xyzzy)
Riassumendo, vi serve:
- un ``COMPAT_SYSCALL_DEFINEn(xyzzy, ...)`` per il punto d'accesso
*compatibile*
- un prototipo in ``include/linux/compat.h``
- (se necessario) una struttura di compatibilità a 32-bit in
``include/linux/compat.h``
- una voce ``__SC_COMP``, e non ``__SYSCALL``, in
``include/uapi/asm-generic/unistd.h``
Compatibilità delle chiamate di sistema (x86)
---------------------------------------------
Per collegare una chiamata di sistema, su un'architettura x86, con la sua
versione *compatibile*, è necessario aggiustare la voce nella tabella
delle syscall.
Per prima cosa, la voce in ``arch/x86/entry/syscalls/syscall_32.tbl`` prende
un argomento aggiuntivo per indicare che un programma in spazio utente
a 32-bit, eseguito su un kernel a 64-bit, dovrebbe accedere tramite il punto
d'accesso compatibile::
380 i386 xyzzy sys_xyzzy __ia32_compat_sys_xyzzy
Secondo, dovete capire cosa dovrebbe succedere alla nuova chiamata di sistema
per la versione dell'ABI x32. Qui C'è una scelta da fare: gli argomenti
possono corrisponde alla versione a 64-bit o a quella a 32-bit.
Se c'è un puntatore ad un puntatore, la decisione è semplice: x32 è ILP32,
quindi gli argomenti dovrebbero corrispondere a quelli a 32-bit, e la voce in
``arch/x86/entry/syscalls/syscall_64.tbl`` sarà divisa cosicché i programmi
x32 eseguano la chiamata *compatibile*::
333 64 xyzzy sys_xyzzy
...
555 x32 xyzzy __x32_compat_sys_xyzzy
Se non ci sono puntatori, allora è preferibile riutilizzare la chiamata di
sistema a 64-bit per l'ABI x32 (e di conseguenza la voce in
arch/x86/entry/syscalls/syscall_64.tbl rimane immutata).
In ambo i casi, dovreste verificare che i tipi usati dagli argomenti
abbiano un'esatta corrispondenza da x32 (-mx32) al loro equivalente a
32-bit (-m32) o 64-bit (-m64).
Chiamate di sistema che ritornano altrove
-----------------------------------------
Nella maggior parte delle chiamate di sistema, al termine della loro
esecuzione, i programmi in spazio utente riprendono esattamente dal punto
in cui si erano interrotti -- quindi dall'istruzione successiva, con lo
stesso *stack* e con la maggior parte del registri com'erano stati
lasciati prima della chiamata di sistema, e anche con la stessa memoria
virtuale.
Tuttavia, alcune chiamata di sistema fanno le cose in modo differente.
Potrebbero ritornare ad un punto diverso (``rt_sigreturn``) o cambiare
la memoria in spazio utente (``fork``/``vfork``/``clone``) o perfino
l'architettura del programma (``execve``/``execveat``).
Per permettere tutto ciò, l'implementazione nel kernel di questo tipo di
chiamate di sistema potrebbero dover salvare e ripristinare registri
aggiuntivi nello *stack* del kernel, permettendo così un controllo completo
su dove e come l'esecuzione dovrà continuare dopo l'esecuzione della
chiamata di sistema.
Queste saranno specifiche per ogni architettura, ma tipicamente si definiscono
dei punti d'accesso in *assembly* per salvare/ripristinare i registri
aggiuntivi e quindi chiamare il vero punto d'accesso per la chiamata di
sistema.
Per l'architettura x86_64, questo è implementato come un punto d'accesso
``stub_xyzzy`` in ``arch/x86/entry/entry_64.S``, e la voce nella tabella
di syscall (``arch/x86/entry/syscalls/syscall_64.tbl``) verrà corretta di
conseguenza::
333 common xyzzy stub_xyzzy
L'equivalente per programmi a 32-bit eseguiti su un kernel a 64-bit viene
normalmente chiamato ``stub32_xyzzy`` e implementato in
``arch/x86/entry/entry_64_compat.S`` con la corrispondente voce nella tabella
di syscall ``arch/x86/entry/syscalls/syscall_32.tbl`` corretta nel
seguente modo::
380 i386 xyzzy sys_xyzzy stub32_xyzzy
Se una chiamata di sistema necessita di un livello di compatibilità (come
nella sezione precedente), allora la versione ``stub32_`` deve invocare
la versione ``compat_sys_`` piuttosto che quella nativa a 64-bit. In aggiunta,
se l'implementazione dell'ABI x32 è diversa da quella x86_64, allora la sua
voce nella tabella di syscall dovrà chiamare uno *stub* che invoca la versione
``compat_sys_``,
Per completezza, sarebbe carino impostare una mappatura cosicché
*user-mode* Linux (UML) continui a funzionare -- la sua tabella di syscall
farà riferimento a stub_xyzzy, ma UML non include l'implementazione
in ``arch/x86/entry/entry_64.S`` (perché UML simula i registri eccetera).
Correggerlo è semplice, basta aggiungere una #define in
``arch/x86/um/sys_call_table_64.c``::
#define stub_xyzzy sys_xyzzy
Altri dettagli
--------------
La maggior parte dei kernel tratta le chiamate di sistema allo stesso modo,
ma possono esserci rare eccezioni per le quali potrebbe essere necessario
l'aggiornamento della vostra chiamata di sistema.
Il sotto-sistema di controllo (*audit subsystem*) è uno di questi casi
speciali; esso include (per architettura) funzioni che classificano alcuni
tipi di chiamate di sistema -- in particolare apertura dei file
(``open``/``openat``), esecuzione dei programmi (``execve``/``exeveat``)
oppure multiplatori di socket (``socketcall``). Se la vostra nuova chiamata
di sistema è simile ad una di queste, allora il sistema di controllo dovrebbe
essere aggiornato.
Più in generale, se esiste una chiamata di sistema che è simile alla vostra,
vale la pena fare una ricerca con ``grep`` su tutto il kernel per la chiamata
di sistema esistente per verificare che non ci siano altri casi speciali.
Verifica
--------
Una nuova chiamata di sistema dev'essere, ovviamente, provata; è utile fornire
ai revisori un programma in spazio utente che mostri l'uso della chiamata di
sistema. Un buon modo per combinare queste cose è quello di aggiungere un
semplice programma di auto-verifica in una nuova cartella in
``tools/testing/selftests/``.
Per una nuova chiamata di sistema, ovviamente, non ci sarà alcuna funzione
in libc e quindi il programma di verifica dovrà invocarla usando ``syscall()``;
inoltre, se la nuova chiamata di sistema prevede un nuova struttura dati
visibile in spazio utente, il file d'intestazione necessario dev'essere
installato al fine di compilare il programma.
Assicuratevi che il programma di auto-verifica possa essere eseguito
correttamente su tutte le architetture supportate. Per esempio, verificate che
funzioni quando viene compilato per x86_64 (-m64), x86_32 (-m32) e x32 (-mx32).
Al fine di una più meticolosa ed estesa verifica della nuova funzionalità,
dovreste considerare l'aggiunta di nuove verifica al progetto 'Linux Test',
oppure al progetto xfstests per cambiamenti relativi al filesystem.
- https://linux-test-project.github.io/
- git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git
Pagine man
----------
Tutte le nuove chiamate di sistema dovrebbero avere una pagina man completa,
idealmente usando i marcatori groff, ma anche il puro testo può andare. Se
state usando groff, è utile che includiate nella email di presentazione una
versione già convertita in formato ASCII: semplificherà la vita dei revisori.
Le pagine man dovrebbero essere in copia-conoscenza verso
linux-man@vger.kernel.org
Per maggiori dettagli, leggere
https://www.kernel.org/doc/man-pages/patches.html
Non invocate chiamate di sistema dal kernel
-------------------------------------------
Le chiamate di sistema sono, come già detto prima, punti di interazione fra
lo spazio utente e il kernel. Perciò, le chiamate di sistema come
``sys_xyzzy()`` o ``compat_sys_xyzzy()`` dovrebbero essere chiamate solo dallo
spazio utente attraverso la tabella syscall, ma non da nessun altro punto nel
kernel. Se la nuova funzionalità è utile all'interno del kernel, per esempio
dev'essere condivisa fra una vecchia e una nuova chiamata di sistema o
dev'essere utilizzata da una chiamata di sistema e la sua variante compatibile,
allora dev'essere implementata come una funzione di supporto
(*helper function*) (per esempio ``kern_xyzzy()``). Questa funzione potrà
essere chiamata dallo *stub* (``sys_xyzzy()``), dalla variante compatibile
(``compat_sys_xyzzy()``), e/o da altri parti del kernel.
Sui sistemi x86 a 64-bit, a partire dalla versione v4.17 è un requisito
fondamentale quello di non invocare chiamate di sistema all'interno del kernel.
Esso usa una diversa convenzione per l'invocazione di chiamate di sistema dove
``struct pt_regs`` viene decodificata al volo in una funzione che racchiude
la chiamata di sistema la quale verrà eseguita successivamente.
Questo significa che verranno passati solo i parametri che sono davvero
necessari ad una specifica chiamata di sistema, invece che riempire ogni volta
6 registri del processore con contenuti presi dallo spazio utente (potrebbe
causare seri problemi nella sequenza di chiamate).
Inoltre, le regole su come i dati possano essere usati potrebbero differire
fra il kernel e l'utente. Questo è un altro motivo per cui invocare
``sys_xyzzy()`` è generalmente una brutta idea.
Eccezioni a questa regola vengono accettate solo per funzioni d'architetture
che surclassano quelle generiche, per funzioni d'architettura di compatibilità,
o per altro codice in arch/
Riferimenti e fonti
-------------------
- Articolo di Michael Kerris su LWN sull'uso dell'argomento flags nelle
chiamate di sistema: https://lwn.net/Articles/585415/
- Articolo di Michael Kerris su LWN su come gestire flag sconosciuti in
una chiamata di sistema: https://lwn.net/Articles/588444/
- Articolo di Jake Edge su LWN che descrive i limiti degli argomenti a 64-bit
delle chiamate di sistema: https://lwn.net/Articles/311630/
- Una coppia di articoli di David Drysdale che descrivono i dettagli del
percorso implementativo di una chiamata di sistema per la versione v3.14:
- https://lwn.net/Articles/604287/
- https://lwn.net/Articles/604515/
- Requisiti specifici alle architetture sono discussi nella pagina man
:manpage:`syscall(2)` :
http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES
- Collezione di email di Linux Torvalds sui problemi relativi a ``ioctl()``:
http://yarchive.net/comp/linux/ioctl.html
- "Come non inventare interfacce del kernel", Arnd Bergmann,
http://www.ukuug.org/events/linux2007/2007/papers/Bergmann.pdf
- Articolo di Michael Kerris su LWN sull'evitare nuovi usi di CAP_SYS_ADMIN:
https://lwn.net/Articles/486306/
- Raccomandazioni da Andrew Morton circa il fatto che tutte le informazioni
su una nuova chiamata di sistema dovrebbero essere contenute nello stesso
filone di discussione di email: https://lkml.org/lkml/2014/7/24/641
- Raccomandazioni da Michael Kerrisk circa il fatto che le nuove chiamate di
sistema dovrebbero avere una pagina man: https://lkml.org/lkml/2014/6/13/309
- Consigli da Thomas Gleixner sul fatto che il collegamento all'architettura
x86 dovrebbe avvenire in un *commit* differente:
https://lkml.org/lkml/2014/11/19/254
- Consigli da Greg Kroah-Hartman circa la bontà d'avere una pagina man e un
programma di auto-verifica per le nuove chiamate di sistema:
https://lkml.org/lkml/2014/3/19/710
- Discussione di Michael Kerrisk sulle nuove chiamate di sistema contro
le estensioni :manpage:`prctl(2)`: https://lkml.org/lkml/2014/6/3/411
- Consigli da Ingo Molnar che le chiamate di sistema con più argomenti
dovrebbero incapsularli in una struttura che includa un argomento
*size* per garantire l'estensibilità futura:
https://lkml.org/lkml/2015/7/30/117
- Un certo numero di casi strani emersi dall'uso (riuso) dei flag O_*:
- commit 75069f2b5bfb ("vfs: renumber FMODE_NONOTIFY and add to uniqueness
check")
- commit 12ed2e36c98a ("fanotify: FMODE_NONOTIFY and __O_SYNC in sparc
conflict")
- commit bb458c644a59 ("Safer ABI for O_TMPFILE")
- Discussion from Matthew Wilcox about restrictions on 64-bit arguments:
https://lkml.org/lkml/2008/12/12/187
- Raccomandazioni da Greg Kroah-Hartman sul fatto che i flag sconosciuti dovrebbero
essere controllati: https://lkml.org/lkml/2014/7/17/577
- Raccomandazioni da Linus Torvalds che le chiamate di sistema x32 dovrebbero
favorire la compatibilità con le versioni a 64-bit piuttosto che quelle a 32-bit:
https://lkml.org/lkml/2011/8/31/244
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment