162306a36Sopenharmony_ci.. include:: ../disclaimer-ita.rst
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci:Original: Documentation/process/botching-up-ioctls.rst
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci==========================================
662306a36Sopenharmony_ci(Come evitare di) Raffazzonare delle ioctl
762306a36Sopenharmony_ci==========================================
862306a36Sopenharmony_ci
962306a36Sopenharmony_ciPreso da: https://blog.ffwll.ch/2013/11/botching-up-ioctls.html
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciScritto da : Daniel Vetter, Copyright © 2013 Intel Corporation
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciUna cosa che gli sviluppatori del sottosistema grafico del kernel Linux hanno
1462306a36Sopenharmony_ciimparato negli ultimi anni è l'inutilità di cercare di creare un'interfaccia
1562306a36Sopenharmony_ciunificata per gestire la memoria e le unità esecutive di diverse GPU. Dunque,
1662306a36Sopenharmony_cioggigiorno ogni driver ha il suo insieme di ioctl per allocare memoria ed
1762306a36Sopenharmony_ciinviare dei programmi alla GPU. Il che è va bene dato che non c'è più un insano
1862306a36Sopenharmony_cisistema che finge di essere generico, ma al suo posto ci sono interfacce
1962306a36Sopenharmony_cidedicate. Ma al tempo stesso è più facile incasinare le cose.
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciPer evitare di ripetere gli stessi errori ho preso nota delle lezioni imparate
2262306a36Sopenharmony_cimentre raffazzonavo il driver drm/i915. La maggior parte di queste lezioni si
2362306a36Sopenharmony_cifocalizzano sui tecnicismi e non sulla visione d'insieme, come le discussioni
2462306a36Sopenharmony_ciriguardo al modo migliore per implementare una ioctl per inviare compiti alla
2562306a36Sopenharmony_ciGPU. Probabilmente, ogni sviluppatore di driver per GPU dovrebbe imparare queste
2662306a36Sopenharmony_cilezioni in autonomia.
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ciPrerequisiti
3062306a36Sopenharmony_ci------------
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciPrima i prerequisiti. Seguite i seguenti suggerimenti se non volete fallire in
3362306a36Sopenharmony_cipartenza e ritrovarvi ad aggiungere un livello di compatibilità a 32-bit.
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci* Usate solamente interi a lunghezza fissa. Per evitare i conflitti coi tipi
3662306a36Sopenharmony_ci  definiti nello spazio utente, il kernel definisce alcuni tipi speciali, come:
3762306a36Sopenharmony_ci  ``__u32``, ``__s64``. Usateli.
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci* Allineate tutto alla lunghezza naturale delle piattaforma in uso e riempite
4062306a36Sopenharmony_ci  esplicitamente i vuoti. Non necessariamente le piattaforme a 32-bit allineano
4162306a36Sopenharmony_ci  i valori a 64-bit rispettandone l'allineamento, ma le piattaforme a 64-bit lo
4262306a36Sopenharmony_ci  fanno. Dunque, per farlo correttamente in entrambe i casi dobbiamo sempre
4362306a36Sopenharmony_ci  riempire i vuoti.
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci* Se una struttura dati contiene valori a 64-bit, allora fate si che la sua
4662306a36Sopenharmony_ci  dimensione sia allineata a 64-bit, altrimenti la sua dimensione varierà su
4762306a36Sopenharmony_ci  sistemi a 32-bit e 64-bit. Avere una dimensione differente causa problemi
4862306a36Sopenharmony_ci  quando si passano vettori di strutture dati al kernel, o quando il kernel
4962306a36Sopenharmony_ci  effettua verifiche sulla dimensione (per esempio il sistema drm lo fa).
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci* I puntatori sono di tipo ``__u64``, con un *cast* da/a ``uintptr_t`` da lato
5262306a36Sopenharmony_ci  spazio utente e da/a ``void __user *`` nello spazio kernel. Sforzatevi il più
5362306a36Sopenharmony_ci  possibile per non ritardare la conversione, o peggio maneggiare ``__u64`` nel
5462306a36Sopenharmony_ci  vostro codice perché questo riduce le verifiche che strumenti come sparse
5562306a36Sopenharmony_ci  possono effettuare. La macro u64_to_user_ptr() può essere usata nel kernel
5662306a36Sopenharmony_ci  per evitare avvisi riguardo interi e puntatori di dimensioni differenti.
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciLe Basi
6062306a36Sopenharmony_ci-------
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciCon la gioia d'aver evitato un livello di compatibilità, possiamo ora dare uno
6362306a36Sopenharmony_cisguardo alle basi. Trascurare questi punti renderà difficile la gestione della
6462306a36Sopenharmony_cicompatibilità all'indietro ed in avanti. E dato che sbagliare al primo colpo è
6562306a36Sopenharmony_cigarantito, dovrete rivisitare il codice o estenderlo per ogni interfaccia.
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci* Abbiate un modo chiaro per capire dallo spazio utente se una nuova ioctl, o
6862306a36Sopenharmony_ci  l'estensione di una esistente, sia supportata dal kernel in esecuzione. Se non
6962306a36Sopenharmony_ci  potete fidarvi del fatto che un vecchio kernel possa rifiutare correttamente
7062306a36Sopenharmony_ci  un nuovo *flag*, modalità, o ioctl, (probabilmente perché avevate raffazzonato
7162306a36Sopenharmony_ci  qualcosa nel passato) allora dovrete implementare nel driver un meccanismo per
7262306a36Sopenharmony_ci  notificare quali funzionalità sono supportate, o in alternativa un numero di
7362306a36Sopenharmony_ci  versione.
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci* Abbiate un piano per estendere le ioctl con nuovi *flag* o campi alla fine di
7662306a36Sopenharmony_ci  una struttura dati. Il sistema drm verifica la dimensione di ogni ioctl in
7762306a36Sopenharmony_ci  arrivo, ed estende con zeri ogni incongruenza fra kernel e spazio utente.
7862306a36Sopenharmony_ci  Questo aiuta, ma non è una soluzione completa dato che uno spazio utente nuovo
7962306a36Sopenharmony_ci  su un kernel vecchio non noterebbe che i campi nuovi alla fine della struttura
8062306a36Sopenharmony_ci  vengono ignorati. Dunque, anche questo avrà bisogno di essere notificato dal
8162306a36Sopenharmony_ci  driver allo spazio utente.
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci* Verificate tutti i campi e *flag* inutilizzati ed i riempimenti siano a 0,
8462306a36Sopenharmony_ci  altrimenti rifiutare la ioctl. Se non lo fate il vostro bel piano per
8562306a36Sopenharmony_ci  estendere le ioctl andrà a rotoli dato che qualcuno userà delle ioctl con
8662306a36Sopenharmony_ci  strutture dati con valori casuali dallo stack nei campi inutilizzati. Il che
8762306a36Sopenharmony_ci  si traduce nell'avere questi campi nell'ABI, e la cui unica utilità sarà
8862306a36Sopenharmony_ci  quella di contenere spazzatura. Per questo dovrete esplicitamente riempire i
8962306a36Sopenharmony_ci  vuoti di tutte le vostre strutture dati, anche se non le userete in un
9062306a36Sopenharmony_ci  vettore. Il riempimento fatto dal compilatore potrebbe contenere valori
9162306a36Sopenharmony_ci  casuali.
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci* Abbiate un semplice codice di test per ognuno dei casi sopracitati.
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciDivertirsi coi percorsi d'errore
9762306a36Sopenharmony_ci--------------------------------
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciOggigiorno non ci sono più scuse rimaste per permettere ai driver drm di essere
10062306a36Sopenharmony_cisfruttati per diventare root. Questo significa che dobbiamo avere una completa
10162306a36Sopenharmony_civalidazione degli input e gestire in modo robusto i percorsi - tanto le GPU
10262306a36Sopenharmony_cimoriranno comunque nel più strano dei casi particolari:
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci * Le ioctl devono verificare l'overflow dei vettori. Inoltre, per i valori
10562306a36Sopenharmony_ci   interi si devono verificare *overflow*, *underflow*, e *clamping*. Il
10662306a36Sopenharmony_ci   classico esempio è l'inserimento direttamente nell'hardware di valori di
10762306a36Sopenharmony_ci   posizionamento di un'immagine *sprite* quando l'hardware supporta giusto 12
10862306a36Sopenharmony_ci   bit, o qualcosa del genere. Tutto funzionerà finché qualche strano *display
10962306a36Sopenharmony_ci   server* non decide di preoccuparsi lui stesso del *clamping* e il cursore
11062306a36Sopenharmony_ci   farà il giro dello schermo.
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci * Avere un test semplice per ogni possibile fallimento della vostra ioctl.
11362306a36Sopenharmony_ci   Verificate che il codice di errore rispetti le aspettative. Ed infine,
11462306a36Sopenharmony_ci   assicuratevi che verifichiate un solo percorso sbagliato per ogni sotto-test
11562306a36Sopenharmony_ci   inviando comunque dati corretti. Senza questo, verifiche precedenti
11662306a36Sopenharmony_ci   potrebbero rigettare la ioctl troppo presto, impedendo l'esecuzione del
11762306a36Sopenharmony_ci   codice che si voleva effettivamente verificare, rischiando quindi di
11862306a36Sopenharmony_ci   mascherare bachi e regressioni.
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci * Fate si che tutte le vostre ioctl siano rieseguibili. Prima di tutto X adora
12162306a36Sopenharmony_ci   i segnali; secondo questo vi permetterà di verificare il 90% dei percorsi
12262306a36Sopenharmony_ci   d'errore interrompendo i vostri test con dei segnali. Grazie all'amore di X
12362306a36Sopenharmony_ci   per i segnali, otterrete gratuitamente un eccellente copertura di base per
12462306a36Sopenharmony_ci   tutti i vostri percorsi d'errore. Inoltre, siate consistenti sul modo di
12562306a36Sopenharmony_ci   gestire la riesecuzione delle ioctl - per esempio, drm ha una piccola
12662306a36Sopenharmony_ci   funzione di supporto `drmIoctl` nella sua librerie in spazio utente. Il
12762306a36Sopenharmony_ci   driver i915 l'abbozza con l'ioctl `set_tiling`, ed ora siamo inchiodati per
12862306a36Sopenharmony_ci   sempre con una semantica arcana sia nel kernel che nello spazio utente.
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci * Se non potete rendere un pezzo di codice rieseguibile, almeno rendete
13262306a36Sopenharmony_ci   possibile la sua interruzione. Le GPU moriranno e i vostri utenti non vi
13362306a36Sopenharmony_ci   apprezzeranno affatto se tenete in ostaggio il loro scatolotto (mediante un
13462306a36Sopenharmony_ci   processo X insopprimibile). Se anche recuperare lo stato è troppo complicato,
13562306a36Sopenharmony_ci   allora implementate una scadenza oppure come ultima spiaggia una rete di
13662306a36Sopenharmony_ci   sicurezza per rilevare situazioni di stallo quando l'hardware da di matto.
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci * Preparate dei test riguardo ai casi particolarmente estremi nel codice di
13962306a36Sopenharmony_ci   recupero del sistema - è troppo facile create uno stallo fra il vostro codice
14062306a36Sopenharmony_ci   anti-stallo e un processo scrittore.
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ciTempi, attese e mancate scadenze
14462306a36Sopenharmony_ci--------------------------------
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciLe GPU fanno quasi tutto in modo asincrono, dunque dobbiamo regolare le
14762306a36Sopenharmony_cioperazioni ed attendere quelle in sospeso. Questo è davvero difficile; al
14862306a36Sopenharmony_cimomento nessuna delle ioctl supportante dal driver drm/i915 riesce a farlo
14962306a36Sopenharmony_ciperfettamente, il che significa che qui ci sono ancora una valanga di lezioni da
15062306a36Sopenharmony_ciapprendere.
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci * Per fare riferimento al tempo usate sempre ``CLOCK_MONOTONIC``. Oggigiorno
15362306a36Sopenharmony_ci   questo è quello che viene usato di base da alsa, drm, e v4l. Tuttavia,
15462306a36Sopenharmony_ci   lasciate allo spazio utente la possibilità di capire quali *timestamp*
15562306a36Sopenharmony_ci   derivano da domini temporali diversi come il vostro orologio di sistema
15662306a36Sopenharmony_ci   (fornito dal kernel) oppure un contatore hardware indipendente da qualche
15762306a36Sopenharmony_ci   parte. Gli orologi divergeranno, ma con questa informazione gli strumenti di
15862306a36Sopenharmony_ci   analisi delle prestazioni possono compensare il problema. Se il vostro spazio
15962306a36Sopenharmony_ci   utente può ottenere i valori grezzi degli orologi, allora considerate di
16062306a36Sopenharmony_ci   esporre anch'essi.
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci * Per descrivere il tempo, usate ``__s64`` per i secondi e ``__u64`` per i
16362306a36Sopenharmony_ci   nanosecondi. Non è il modo migliore per specificare il tempo, ma è
16462306a36Sopenharmony_ci   praticamente uno standard.
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci * Verificate che gli input di valori temporali siano normalizzati, e se non lo
16762306a36Sopenharmony_ci   sono scartateli. Fate attenzione perché la struttura dati ``struct ktime``
16862306a36Sopenharmony_ci   del kernel usa interi con segni sia per i secondi che per i nanosecondi.
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci * Per le scadenze (*timeout*) usate valori temporali assoluti. Se siete dei
17162306a36Sopenharmony_ci   bravi ragazzi e avete reso la vostra ioctl rieseguibile, allora i tempi
17262306a36Sopenharmony_ci   relativi tendono ad essere troppo grossolani e a causa degli arrotondamenti
17362306a36Sopenharmony_ci   potrebbero estendere in modo indefinito i tempi di attesa ad ogni
17462306a36Sopenharmony_ci   riesecuzione. Particolarmente vero se il vostro orologio di riferimento è
17562306a36Sopenharmony_ci   qualcosa di molto lento come il contatore di *frame*. Con la giacca da
17662306a36Sopenharmony_ci   avvocato delle specifiche diremmo che questo non è un baco perché tutte le
17762306a36Sopenharmony_ci   scadenze potrebbero essere estese - ma sicuramente gli utenti vi odieranno
17862306a36Sopenharmony_ci   quando le animazioni singhiozzano.
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci * Considerate l'idea di eliminare tutte le ioctl sincrone con scadenze, e di
18162306a36Sopenharmony_ci   sostituirle con una versione asincrona il cui stato può essere consultato
18262306a36Sopenharmony_ci   attraverso il descrittore di file mediante ``poll``. Questo approccio si
18362306a36Sopenharmony_ci   sposa meglio in un applicazione guidata dagli eventi.
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci * Sviluppate dei test per i casi estremi, specialmente verificate che i valori
18662306a36Sopenharmony_ci   di ritorno per gli eventi già completati, le attese terminate con successo, e
18762306a36Sopenharmony_ci   le attese scadute abbiano senso e servano ai vostri scopi.
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ciNon perdere risorse
19162306a36Sopenharmony_ci-------------------
19262306a36Sopenharmony_ciNel suo piccolo il driver drm implementa un sistema operativo specializzato per
19362306a36Sopenharmony_cicerte GPU. Questo significa che il driver deve esporre verso lo spazio
19462306a36Sopenharmony_ciutente tonnellate di agganci per accedere ad oggetti e altre risorse. Farlo
19562306a36Sopenharmony_cicorrettamente porterà con se alcune insidie:
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci * Collegate sempre la vita di una risorsa creata dinamicamente, a quella del
19862306a36Sopenharmony_ci   descrittore di file. Considerate una mappatura 1:1 se la vostra risorsa
19962306a36Sopenharmony_ci   dev'essere condivisa fra processi - passarsi descrittori di file sul socket
20062306a36Sopenharmony_ci   unix semplifica la gestione anche per lo spazio utente.
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci * Dev'esserci sempre Il supporto ``O_CLOEXEC``.
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci * Assicuratevi di avere abbastanza isolamento fra utenti diversi. Di base
20562306a36Sopenharmony_ci   impostate uno spazio dei nomi riservato per ogni descrittore di file, il che
20662306a36Sopenharmony_ci   forzerà ogni condivisione ad essere esplicita. Usate uno spazio più globale
20762306a36Sopenharmony_ci   per dispositivo solo se gli oggetti sono effettivamente unici per quel
20862306a36Sopenharmony_ci   dispositivo. Un controesempio viene dall'interfaccia drm modeset, dove
20962306a36Sopenharmony_ci   oggetti specifici di dispositivo, come i connettori, condividono uno spazio
21062306a36Sopenharmony_ci   dei nomi con oggetti per il *framebuffer*, ma questi non sono per niente
21162306a36Sopenharmony_ci   condivisi. Uno spazio separato, privato di base, per i *framebuffer* sarebbe
21262306a36Sopenharmony_ci   stato meglio.
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci * Pensate all'identificazione univoca degli agganci verso lo spazio utente. Per
21562306a36Sopenharmony_ci   esempio, per la maggior parte dei driver drm, si considera fallace la doppia
21662306a36Sopenharmony_ci   sottomissione di un oggetto allo stesso comando ioctl. Ma per evitarlo, se
21762306a36Sopenharmony_ci   gli oggetti sono condivisibili, lo spazio utente ha bisogno di sapere se il
21862306a36Sopenharmony_ci   driver ha importato un oggetto da un altro processo. Non l'ho ancora provato,
21962306a36Sopenharmony_ci   ma considerate l'idea di usare il numero di inode come identificatore per i
22062306a36Sopenharmony_ci   descrittori di file condivisi - che poi è come si distinguono i veri file.
22162306a36Sopenharmony_ci   Sfortunatamente, questo richiederebbe lo sviluppo di un vero e proprio
22262306a36Sopenharmony_ci   filesystem virtuale nel kernel.
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ciUltimo, ma non meno importante
22662306a36Sopenharmony_ci------------------------------
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ciNon tutti i problemi si risolvono con una nuova ioctl:
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci* Pensateci su due o tre volte prima di implementare un'interfaccia privata per
23162306a36Sopenharmony_ci  un driver. Ovviamente è molto più veloce seguire questa via piuttosto che
23262306a36Sopenharmony_ci  buttarsi in lunghe discussioni alla ricerca di una soluzione più generica. Ed
23362306a36Sopenharmony_ci  a volte un'interfaccia privata è quello che serve per sviluppare un nuovo
23462306a36Sopenharmony_ci  concetto. Ma alla fine, una volta che c'è un'interfaccia generica a
23562306a36Sopenharmony_ci  disposizione finirete per mantenere due interfacce. Per sempre.
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci* Considerate interfacce alternative alle ioctl. Gli attributi sysfs sono molto
23862306a36Sopenharmony_ci  meglio per impostazioni che sono specifiche di un dispositivo, o per
23962306a36Sopenharmony_ci  sotto-oggetti con una vita piuttosto statica (come le uscite dei connettori in
24062306a36Sopenharmony_ci  drm con tutti gli attributi per la sovrascrittura delle rilevazioni). O magari
24162306a36Sopenharmony_ci  solo il vostro sistema di test ha bisogno di una certa interfaccia, e allora
24262306a36Sopenharmony_ci  debugfs (che non ha un'interfaccia stabile) sarà la soluzione migliore.
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ciPer concludere. Questo gioco consiste nel fare le cose giuste fin da subito,
24562306a36Sopenharmony_cidato che se il vostro driver diventa popolare e la piattaforma hardware longeva
24662306a36Sopenharmony_cifinirete per mantenere le vostre ioctl per sempre. Potrete tentare di deprecare
24762306a36Sopenharmony_cialcune orribili ioctl, ma ci vorranno anni per riuscirci effettivamente. E
24862306a36Sopenharmony_ciancora, altri anni prima che sparisca l'ultimo utente capace di lamentarsi per
24962306a36Sopenharmony_ciuna regressione.
250