~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/translations/it_IT/process/botching-up-ioctls.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 .. include:: ../disclaimer-ita.rst
  2 
  3 :Original: Documentation/process/botching-up-ioctls.rst
  4 
  5 ==========================================
  6 (Come evitare di) Raffazzonare delle ioctl
  7 ==========================================
  8 
  9 Preso da: https://blog.ffwll.ch/2013/11/botching-up-ioctls.html
 10 
 11 Scritto da : Daniel Vetter, Copyright © 2013 Intel Corporation
 12 
 13 Una cosa che gli sviluppatori del sottosistema grafico del kernel Linux hanno
 14 imparato negli ultimi anni è l'inutilità di cercare di creare un'interfaccia
 15 unificata per gestire la memoria e le unità esecutive di diverse GPU. Dunque,
 16 oggigiorno ogni driver ha il suo insieme di ioctl per allocare memoria ed
 17 inviare dei programmi alla GPU. Il che è va bene dato che non c'è più un insano
 18 sistema che finge di essere generico, ma al suo posto ci sono interfacce
 19 dedicate. Ma al tempo stesso è più facile incasinare le cose.
 20 
 21 Per evitare di ripetere gli stessi errori ho preso nota delle lezioni imparate
 22 mentre raffazzonavo il driver drm/i915. La maggior parte di queste lezioni si
 23 focalizzano sui tecnicismi e non sulla visione d'insieme, come le discussioni
 24 riguardo al modo migliore per implementare una ioctl per inviare compiti alla
 25 GPU. Probabilmente, ogni sviluppatore di driver per GPU dovrebbe imparare queste
 26 lezioni in autonomia.
 27 
 28 
 29 Prerequisiti
 30 ------------
 31 
 32 Prima i prerequisiti. Seguite i seguenti suggerimenti se non volete fallire in
 33 partenza e ritrovarvi ad aggiungere un livello di compatibilità a 32-bit.
 34 
 35 * Usate solamente interi a lunghezza fissa. Per evitare i conflitti coi tipi
 36   definiti nello spazio utente, il kernel definisce alcuni tipi speciali, come:
 37   ``__u32``, ``__s64``. Usateli.
 38 
 39 * Allineate tutto alla lunghezza naturale delle piattaforma in uso e riempite
 40   esplicitamente i vuoti. Non necessariamente le piattaforme a 32-bit allineano
 41   i valori a 64-bit rispettandone l'allineamento, ma le piattaforme a 64-bit lo
 42   fanno. Dunque, per farlo correttamente in entrambe i casi dobbiamo sempre
 43   riempire i vuoti.
 44 
 45 * Se una struttura dati contiene valori a 64-bit, allora fate si che la sua
 46   dimensione sia allineata a 64-bit, altrimenti la sua dimensione varierà su
 47   sistemi a 32-bit e 64-bit. Avere una dimensione differente causa problemi
 48   quando si passano vettori di strutture dati al kernel, o quando il kernel
 49   effettua verifiche sulla dimensione (per esempio il sistema drm lo fa).
 50 
 51 * I puntatori sono di tipo ``__u64``, con un *cast* da/a ``uintptr_t`` da lato
 52   spazio utente e da/a ``void __user *`` nello spazio kernel. Sforzatevi il più
 53   possibile per non ritardare la conversione, o peggio maneggiare ``__u64`` nel
 54   vostro codice perché questo riduce le verifiche che strumenti come sparse
 55   possono effettuare. La macro u64_to_user_ptr() può essere usata nel kernel
 56   per evitare avvisi riguardo interi e puntatori di dimensioni differenti.
 57 
 58 
 59 Le Basi
 60 -------
 61 
 62 Con la gioia d'aver evitato un livello di compatibilità, possiamo ora dare uno
 63 sguardo alle basi. Trascurare questi punti renderà difficile la gestione della
 64 compatibilità all'indietro ed in avanti. E dato che sbagliare al primo colpo è
 65 garantito, dovrete rivisitare il codice o estenderlo per ogni interfaccia.
 66 
 67 * Abbiate un modo chiaro per capire dallo spazio utente se una nuova ioctl, o
 68   l'estensione di una esistente, sia supportata dal kernel in esecuzione. Se non
 69   potete fidarvi del fatto che un vecchio kernel possa rifiutare correttamente
 70   un nuovo *flag*, modalità, o ioctl, (probabilmente perché avevate raffazzonato
 71   qualcosa nel passato) allora dovrete implementare nel driver un meccanismo per
 72   notificare quali funzionalità sono supportate, o in alternativa un numero di
 73   versione.
 74 
 75 * Abbiate un piano per estendere le ioctl con nuovi *flag* o campi alla fine di
 76   una struttura dati. Il sistema drm verifica la dimensione di ogni ioctl in
 77   arrivo, ed estende con zeri ogni incongruenza fra kernel e spazio utente.
 78   Questo aiuta, ma non è una soluzione completa dato che uno spazio utente nuovo
 79   su un kernel vecchio non noterebbe che i campi nuovi alla fine della struttura
 80   vengono ignorati. Dunque, anche questo avrà bisogno di essere notificato dal
 81   driver allo spazio utente.
 82 
 83 * Verificate tutti i campi e *flag* inutilizzati ed i riempimenti siano a 0,
 84   altrimenti rifiutare la ioctl. Se non lo fate il vostro bel piano per
 85   estendere le ioctl andrà a rotoli dato che qualcuno userà delle ioctl con
 86   strutture dati con valori casuali dallo stack nei campi inutilizzati. Il che
 87   si traduce nell'avere questi campi nell'ABI, e la cui unica utilità sarà
 88   quella di contenere spazzatura. Per questo dovrete esplicitamente riempire i
 89   vuoti di tutte le vostre strutture dati, anche se non le userete in un
 90   vettore. Il riempimento fatto dal compilatore potrebbe contenere valori
 91   casuali.
 92 
 93 * Abbiate un semplice codice di test per ognuno dei casi sopracitati.
 94 
 95 
 96 Divertirsi coi percorsi d'errore
 97 --------------------------------
 98 
 99 Oggigiorno non ci sono più scuse rimaste per permettere ai driver drm di essere
100 sfruttati per diventare root. Questo significa che dobbiamo avere una completa
101 validazione degli input e gestire in modo robusto i percorsi - tanto le GPU
102 moriranno comunque nel più strano dei casi particolari:
103 
104  * Le ioctl devono verificare l'overflow dei vettori. Inoltre, per i valori
105    interi si devono verificare *overflow*, *underflow*, e *clamping*. Il
106    classico esempio è l'inserimento direttamente nell'hardware di valori di
107    posizionamento di un'immagine *sprite* quando l'hardware supporta giusto 12
108    bit, o qualcosa del genere. Tutto funzionerà finché qualche strano *display
109    server* non decide di preoccuparsi lui stesso del *clamping* e il cursore
110    farà il giro dello schermo.
111 
112  * Avere un test semplice per ogni possibile fallimento della vostra ioctl.
113    Verificate che il codice di errore rispetti le aspettative. Ed infine,
114    assicuratevi che verifichiate un solo percorso sbagliato per ogni sotto-test
115    inviando comunque dati corretti. Senza questo, verifiche precedenti
116    potrebbero rigettare la ioctl troppo presto, impedendo l'esecuzione del
117    codice che si voleva effettivamente verificare, rischiando quindi di
118    mascherare bachi e regressioni.
119 
120  * Fate si che tutte le vostre ioctl siano rieseguibili. Prima di tutto X adora
121    i segnali; secondo questo vi permetterà di verificare il 90% dei percorsi
122    d'errore interrompendo i vostri test con dei segnali. Grazie all'amore di X
123    per i segnali, otterrete gratuitamente un eccellente copertura di base per
124    tutti i vostri percorsi d'errore. Inoltre, siate consistenti sul modo di
125    gestire la riesecuzione delle ioctl - per esempio, drm ha una piccola
126    funzione di supporto `drmIoctl` nella sua librerie in spazio utente. Il
127    driver i915 l'abbozza con l'ioctl `set_tiling`, ed ora siamo inchiodati per
128    sempre con una semantica arcana sia nel kernel che nello spazio utente.
129 
130 
131  * Se non potete rendere un pezzo di codice rieseguibile, almeno rendete
132    possibile la sua interruzione. Le GPU moriranno e i vostri utenti non vi
133    apprezzeranno affatto se tenete in ostaggio il loro scatolotto (mediante un
134    processo X insopprimibile). Se anche recuperare lo stato è troppo complicato,
135    allora implementate una scadenza oppure come ultima spiaggia una rete di
136    sicurezza per rilevare situazioni di stallo quando l'hardware da di matto.
137 
138  * Preparate dei test riguardo ai casi particolarmente estremi nel codice di
139    recupero del sistema - è troppo facile create uno stallo fra il vostro codice
140    anti-stallo e un processo scrittore.
141 
142 
143 Tempi, attese e mancate scadenze
144 --------------------------------
145 
146 Le GPU fanno quasi tutto in modo asincrono, dunque dobbiamo regolare le
147 operazioni ed attendere quelle in sospeso. Questo è davvero difficile; al
148 momento nessuna delle ioctl supportante dal driver drm/i915 riesce a farlo
149 perfettamente, il che significa che qui ci sono ancora una valanga di lezioni da
150 apprendere.
151 
152  * Per fare riferimento al tempo usate sempre ``CLOCK_MONOTONIC``. Oggigiorno
153    questo è quello che viene usato di base da alsa, drm, e v4l. Tuttavia,
154    lasciate allo spazio utente la possibilità di capire quali *timestamp*
155    derivano da domini temporali diversi come il vostro orologio di sistema
156    (fornito dal kernel) oppure un contatore hardware indipendente da qualche
157    parte. Gli orologi divergeranno, ma con questa informazione gli strumenti di
158    analisi delle prestazioni possono compensare il problema. Se il vostro spazio
159    utente può ottenere i valori grezzi degli orologi, allora considerate di
160    esporre anch'essi.
161 
162  * Per descrivere il tempo, usate ``__s64`` per i secondi e ``__u64`` per i
163    nanosecondi. Non è il modo migliore per specificare il tempo, ma è
164    praticamente uno standard.
165 
166  * Verificate che gli input di valori temporali siano normalizzati, e se non lo
167    sono scartateli. Fate attenzione perché la struttura dati ``struct ktime``
168    del kernel usa interi con segni sia per i secondi che per i nanosecondi.
169 
170  * Per le scadenze (*timeout*) usate valori temporali assoluti. Se siete dei
171    bravi ragazzi e avete reso la vostra ioctl rieseguibile, allora i tempi
172    relativi tendono ad essere troppo grossolani e a causa degli arrotondamenti
173    potrebbero estendere in modo indefinito i tempi di attesa ad ogni
174    riesecuzione. Particolarmente vero se il vostro orologio di riferimento è
175    qualcosa di molto lento come il contatore di *frame*. Con la giacca da
176    avvocato delle specifiche diremmo che questo non è un baco perché tutte le
177    scadenze potrebbero essere estese - ma sicuramente gli utenti vi odieranno
178    quando le animazioni singhiozzano.
179 
180  * Considerate l'idea di eliminare tutte le ioctl sincrone con scadenze, e di
181    sostituirle con una versione asincrona il cui stato può essere consultato
182    attraverso il descrittore di file mediante ``poll``. Questo approccio si
183    sposa meglio in un applicazione guidata dagli eventi.
184 
185  * Sviluppate dei test per i casi estremi, specialmente verificate che i valori
186    di ritorno per gli eventi già completati, le attese terminate con successo, e
187    le attese scadute abbiano senso e servano ai vostri scopi.
188 
189 
190 Non perdere risorse
191 -------------------
192 Nel suo piccolo il driver drm implementa un sistema operativo specializzato per
193 certe GPU. Questo significa che il driver deve esporre verso lo spazio
194 utente tonnellate di agganci per accedere ad oggetti e altre risorse. Farlo
195 correttamente porterà con se alcune insidie:
196 
197  * Collegate sempre la vita di una risorsa creata dinamicamente, a quella del
198    descrittore di file. Considerate una mappatura 1:1 se la vostra risorsa
199    dev'essere condivisa fra processi - passarsi descrittori di file sul socket
200    unix semplifica la gestione anche per lo spazio utente.
201 
202  * Dev'esserci sempre Il supporto ``O_CLOEXEC``.
203 
204  * Assicuratevi di avere abbastanza isolamento fra utenti diversi. Di base
205    impostate uno spazio dei nomi riservato per ogni descrittore di file, il che
206    forzerà ogni condivisione ad essere esplicita. Usate uno spazio più globale
207    per dispositivo solo se gli oggetti sono effettivamente unici per quel
208    dispositivo. Un controesempio viene dall'interfaccia drm modeset, dove
209    oggetti specifici di dispositivo, come i connettori, condividono uno spazio
210    dei nomi con oggetti per il *framebuffer*, ma questi non sono per niente
211    condivisi. Uno spazio separato, privato di base, per i *framebuffer* sarebbe
212    stato meglio.
213 
214  * Pensate all'identificazione univoca degli agganci verso lo spazio utente. Per
215    esempio, per la maggior parte dei driver drm, si considera fallace la doppia
216    sottomissione di un oggetto allo stesso comando ioctl. Ma per evitarlo, se
217    gli oggetti sono condivisibili, lo spazio utente ha bisogno di sapere se il
218    driver ha importato un oggetto da un altro processo. Non l'ho ancora provato,
219    ma considerate l'idea di usare il numero di inode come identificatore per i
220    descrittori di file condivisi - che poi è come si distinguono i veri file.
221    Sfortunatamente, questo richiederebbe lo sviluppo di un vero e proprio
222    filesystem virtuale nel kernel.
223 
224 
225 Ultimo, ma non meno importante
226 ------------------------------
227 
228 Non tutti i problemi si risolvono con una nuova ioctl:
229 
230 * Pensateci su due o tre volte prima di implementare un'interfaccia privata per
231   un driver. Ovviamente è molto più veloce seguire questa via piuttosto che
232   buttarsi in lunghe discussioni alla ricerca di una soluzione più generica. Ed
233   a volte un'interfaccia privata è quello che serve per sviluppare un nuovo
234   concetto. Ma alla fine, una volta che c'è un'interfaccia generica a
235   disposizione finirete per mantenere due interfacce. Per sempre.
236 
237 * Considerate interfacce alternative alle ioctl. Gli attributi sysfs sono molto
238   meglio per impostazioni che sono specifiche di un dispositivo, o per
239   sotto-oggetti con una vita piuttosto statica (come le uscite dei connettori in
240   drm con tutti gli attributi per la sovrascrittura delle rilevazioni). O magari
241   solo il vostro sistema di test ha bisogno di una certa interfaccia, e allora
242   debugfs (che non ha un'interfaccia stabile) sarà la soluzione migliore.
243 
244 Per concludere. Questo gioco consiste nel fare le cose giuste fin da subito,
245 dato che se il vostro driver diventa popolare e la piattaforma hardware longeva
246 finirete per mantenere le vostre ioctl per sempre. Potrete tentare di deprecare
247 alcune orribili ioctl, ma ci vorranno anni per riuscirci effettivamente. E
248 ancora, altri anni prima che sparisca l'ultimo utente capace di lamentarsi per
249 una regressione.

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php