Warning
In caso di dubbi sulla correttezza del contenuto di questa traduzione, l’unico riferimento valido è la documentazione ufficiale in inglese. Per maggiori informazioni consultate le avvertenze.
- Original:
- Translator:
Federico Vaga <federico.vaga@vaga.pv.it>
Spazio dei nomi dei simboli¶
Questo documento descrive come usare lo spazio dei nomi dei simboli per strutturare quello che viene esportato internamente al kernel grazie alle macro della famiglia EXPORT_SYMBOL().
1. Introduzione¶
Lo spazio dei nomi dei simboli è stato introdotto come mezzo per strutturare l’API esposta internamente al kernel. Permette ai manutentori di un sottosistema di organizzare i simboli esportati in diversi spazi di nomi. Questo meccanismo è utile per la documentazione (pensate ad esempio allo spazio dei nomi SUBSYSTEM_DEBUG) così come per limitare la disponibilità di un gruppo di simboli in altre parti del kernel. Ad oggi, i moduli che usano simboli esportati da uno spazio di nomi devono prima importare detto spazio. Altrimenti il kernel, a seconda della configurazione, potrebbe rifiutare di caricare il modulo o avvisare l’utente di un’importazione mancante.
2. Come definire uno spazio dei nomi dei simboli¶
I simboli possono essere esportati in spazi dei nomi usando diversi meccanismi. Tutti questi meccanismi cambiano il modo in cui EXPORT_SYMBOL e simili vengono guidati verso la creazione di voci in ksymtab.
2.1 Usare le macro EXPORT_SYMBOL¶
In aggiunta alle macro EXPORT_SYMBOL() e EXPORT_SYMBOL_GPL(), che permettono
di esportare simboli del kernel nella rispettiva tabella, ci sono
varianti che permettono di esportare simboli all’interno di uno spazio dei
nomi: EXPORT_SYMBOL_NS() ed EXPORT_SYMBOL_NS_GPL(). Queste macro richiedono un
argomento aggiuntivo: lo spazio dei nomi.
Tenete presente che per via dell’espansione delle macro questo argomento deve
essere un simbolo di preprocessore. Per esempio per esportare il
simbolo usb_stor_suspend
nello spazio dei nomi USB_STORAGE
usate:
EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE);
Di conseguenza, nella tabella dei simboli del kernel ci sarà una voce
rappresentata dalla struttura kernel_symbol
che avrà il campo
namespace
(spazio dei nomi) impostato. Un simbolo esportato senza uno spazio
dei nomi avrà questo campo impostato a NULL
. Non esiste uno spazio dei nomi
di base. Il programma modpost
e il codice in kernel/module/main.c usano lo
spazio dei nomi, rispettivamente, durante la compilazione e durante il
caricamento di un modulo.
2.2 Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE¶
Definire lo spazio dei nomi per tutti i simboli di un sottosistema può essere logorante e di difficile manutenzione. Perciò è stato fornito un simbolo di preprocessore di base (DEFAULT_SYMBOL_NAMESPACE), che, se impostato, diventa lo spazio dei simboli di base per tutti gli usi di EXPORT_SYMBOL() ed EXPORT_SYMBOL_GPL() che non specificano esplicitamente uno spazio dei nomi.
Ci sono molti modi per specificare questo simbolo di preprocessore e il loro
uso dipende dalle preferenze del manutentore di un sottosistema. La prima
possibilità è quella di definire il simbolo nel Makefile
del sottosistema.
Per esempio per esportare tutti i simboli definiti in usb-common nello spazio
dei nomi USB_COMMON, si può aggiungere la seguente linea in
drivers/usb/common/Makefile:
ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON
Questo cambierà tutte le macro EXPORT_SYMBOL() ed EXPORT_SYMBOL_GPL(). Invece, un simbolo esportato con EXPORT_SYMBOL_NS() non verrà cambiato e il simbolo verrà esportato nello spazio dei nomi indicato.
Una seconda possibilità è quella di definire il simbolo di preprocessore direttamente nei file da compilare. L’esempio precedente diventerebbe:
#undef DEFAULT_SYMBOL_NAMESPACE
#define DEFAULT_SYMBOL_NAMESPACE USB_COMMON
Questo va messo prima di un qualsiasi uso di EXPORT_SYMBOL.
3. Come usare i simboli esportati attraverso uno spazio dei nomi¶
Per usare i simboli esportati da uno spazio dei nomi, i moduli del kernel devono esplicitamente importare il relativo spazio dei nomi; altrimenti il kernel potrebbe rifiutarsi di caricare il modulo. Il codice del modulo deve usare la macro MODULE_IMPORT_NS per importare lo spazio dei nomi che contiene i simboli desiderati. Per esempio un modulo che usa il simbolo usb_stor_suspend deve importare lo spazio dei nomi USB_STORAGE usando la seguente dichiarazione:
MODULE_IMPORT_NS(USB_STORAGE);
Questo creerà un’etichetta modinfo
per ogni spazio dei nomi
importato. Un risvolto di questo fatto è che gli spazi dei
nomi importati da un modulo possono essere ispezionati tramite
modinfo:
$ modinfo drivers/usb/storage/ums-karma.ko
[...]
import_ns: USB_STORAGE
[...]
Si consiglia di posizionare la dichiarazione MODULE_IMPORT_NS() vicino ai metadati del modulo come MODULE_AUTHOR() o MODULE_LICENSE(). Fate riferimento alla sezione 5. per creare automaticamente le importazioni mancanti.
4. Caricare moduli che usano simboli provenienti da spazi dei nomi¶
Quando un modulo viene caricato (per esempio usando insmod
), il kernel
verificherà la disponibilità di ogni simbolo usato e se lo spazio dei nomi
che potrebbe contenerli è stato importato. Il comportamento di base del kernel
è di rifiutarsi di caricare quei moduli che non importano tutti gli spazi dei
nomi necessari. L’errore verrà annotato e il caricamento fallirà con l’errore
EINVAL. Per caricare i moduli che non soddisfano questo requisito esiste
un’opzione di configurazione: impostare
MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y caricherà i moduli comunque ma
emetterà un avviso.
5. Creare automaticamente la dichiarazione MODULE_IMPORT_NS¶
La mancanza di un’importazione può essere individuata facilmente al momento della compilazione. Infatti, modpost emetterà un avviso se il modulo usa un simbolo da uno spazio dei nomi che non è stato importato. La dichiarazione MODULE_IMPORT_NS() viene solitamente aggiunta in un posto ben definito (assieme agli altri metadati del modulo). Per facilitare la vita di chi scrive moduli (e i manutentori di sottosistemi), esistono uno script e un target make per correggere le importazioni mancanti. Questo può essere fatto con:
$ make nsdeps
Lo scenario tipico di chi scrive un modulo potrebbe essere:
- scrivere codice che dipende da un simbolo appartenente ad uno spazio
dei nomi non importato
- eseguire ``make``
- aver notato un avviso da modpost che parla di un'importazione
mancante
- eseguire ``make nsdeps`` per aggiungere import nel posto giusto
Per i manutentori di sottosistemi che vogliono aggiungere uno spazio dei nomi,
l’approccio è simile. Di nuovo, eseguendo make nsdeps
aggiungerà le
importazioni mancanti nei moduli inclusi nel kernel:
- spostare o aggiungere simboli ad uno spazio dei nomi (per esempio
usando EXPORT_SYMBOL_NS())
- eseguire ``make`` (preferibilmente con allmodconfig per coprire tutti
i moduli del kernel)
- aver notato un avviso da modpost che parla di un'importazione
mancante
- eseguire ``make nsdeps`` per aggiungere import nel posto giusto
Potete anche eseguire nsdeps per moduli esterni. Solitamente si usa così:
$ make -C <path_to_kernel_src> M=$PWD nsdeps