2013-06-10 10 views
7

Sto lavorando su alcuni moduli del kernel linux e ho una domanda relativa a un problema di caricamento circolare.Il caricamento dei simboli esportati può essere ritardato?

Il modulo A carica prima ed esporta molti simboli per l'uso del modulo B o C. Il modulo B o C viene quindi caricato in seguito e i simboli esistono per il loro uso.

Tuttavia, ora trovo che il modulo A richiede un simbolo da entrambi i moduli B o C, ma solo durante il runtime e non è necessario per inizializzare il modulo. Quindi, ovviamente, quando A carica, scopre che il simbolo non esiste ancora. Ho persino avuto il simbolo contrassegnato come extern nel modulo A, ma non ha funzionato neanche.

E 'possibile ritardare il caricamento di un simbolo dopo che il modulo A è stato caricato, anche se non esiste ancora fino a quando non è stato caricato B o C?

risposta

5

Tali situazioni vengono spesso risolte utilizzando i callback.

Supponiamo che il modulo A esporti le funzioni per registrare/annullare la registrazione dei callback. B e/o C usano queste funzioni e forniscono i callback appropriati ad A. Quando è necessario, A controlla se le richiamate sono impostate e le chiama.

Qualcosa di simile (senza gestione degli errori e di chiusura per semplicità):

/* Module A */ 
struct a_ops /* Better to define struct a_ops in a header file */ 
{ 
    void (*needed_func)(void); 
    void (*another_needed_func)(void); 
}; 
... 
struct a_ops ops = { 
    .needed_func = NULL; 
    .another_needed_func = NULL; 
}; 
... 
int a_register_needed_funcs(struct a_ops *a_ops) 
{ 
    ops.needed_func = a_ops->needed_func; 
    ops.another_needed_func = a_ops->another_needed_func; 
} 
EXPORT_SYMBOL(a_register_needed_funcs); 

void a_unregister_needed_funcs() 
{ 
    ops.needed_func = NULL; 
    ops.another_needed_func = NULL; 
} 
EXPORT_SYMBOL(a_unregister_needed_funcs); 

... 
/* Call the specified callbacks when needed: */ 
void do_something(void) 
{ 
    if (ops.needed_func != NULL) { 
     ops.needed_func(); 
    } 
    else { 
      /* the callback is not set, handle this: report error, ignore it or 
      * do something else */ 
      ... 
    } 
} 
... 

/* Modules B and C */ 
/* Their code #includes the file where struct a_ops is defined. 
* The module registers the callbacks, for example, in its init function 
* and unregister in exit function. */ 
... 
static void func(void) 
{ 
    ... 
} 

static void another_func(void) 
{ 
    ... 
} 

struct a_ops my_funcs = { 
    .needed_func = func; 
    .another_needed_func = another_func; 
}; 

int __init my_module_init(void) 
{ 
    ... 
    result = a_register_needed_funcs(&my_funcs); 
    ... 
} 
void __exit my_module_exit(void) 
{ 
    ... 
    a_unregister_needed_funcs(); 
    ... 
} 

Questo è simile alle operazioni sui file e molte altre operazioni di callback nel kernel. Supponiamo che un utente desideri leggere, ad esempio, un dispositivo di carattere gestito da un driver personalizzato. Il kernel corretto (VFS, per essere precisi) riceve la richiesta ma non può gestirlo da sé. Invia la richiesta a quel driver personalizzato che ha registrato le sue richiamate operazione file per quel dispositivo. A sua volta, il driver utilizza le funzioni esportate dal kernel corretto, come cdev_add(), ecc.

1

Se si conosce il tipo/prototipo del simbolo, provare a utilizzare kallsyms_lookup_name() per ottenere un puntatore al simbolo desiderato in fase di esecuzione anziché collegarlo ad esso come un simbolo esterno (che significa che il caricatore lo cerca per caricare tempo). Gli esempi possono essere trovati usando il tuo motore di ricerca preferito.

Problemi correlati