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