it-swarm.it

Come posso trovare le implementazioni delle chiamate di sistema del kernel Linux?

Sto cercando di capire come funziona una funzione, ad esempio mkdir, guardando l'origine del kernel. Questo è un tentativo di comprendere gli interni del kernel e navigare tra le varie funzioni. So che mkdir è definito in sys/stat.h. Ho trovato il prototipo:

/* Create a new directory named PATH, with permission bits MODE.  */
extern int mkdir (__const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));

Ora ho bisogno di vedere in quale file C è implementata questa funzione. Dalla directory di origine, ho provato

ack "int mkdir"

quale visualizzato

security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)

tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)

tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);

Ma nessuno di questi corrisponde alla definizione in sys/stat.h.

Domande

  1. Quale file ha l'implementazione mkdir?
  2. Con una definizione di funzione come sopra, come posso sapere quale file ha l'implementazione? C'è qualche modello che il kernel segue nel definire e implementare i metodi?

NOTA: sto usando il kernel 2.6.36-rc1 .

376
Navaneeth K N

Le chiamate di sistema non vengono gestite come le normali chiamate di funzione. Ci vuole un codice speciale per effettuare la transizione dallo spazio utente allo spazio del kernel, fondamentalmente un po 'di codice assembly in linea iniettato nel programma nel sito di chiamata. Il codice laterale del kernel che "intercetta" la chiamata di sistema è anche roba di basso livello che probabilmente non è necessario comprendere a fondo, almeno all'inizio.

In include/linux/syscalls.h nella directory dei sorgenti del kernel, trovi questo:

asmlinkage long sys_mkdir(const char __user *pathname, int mode);

Quindi in /usr/include/asm*/unistd.h, Trovi questo:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Questo codice dice mkdir(2) è la chiamata di sistema # 83. Vale a dire, le chiamate di sistema sono chiamate per numero, non per indirizzo come con una normale chiamata di funzione all'interno del proprio programma o verso una funzione in una libreria collegata al proprio programma. Il codice di colla di assemblaggio in linea che ho menzionato sopra lo usa per fare il passaggio dallo spazio utente a quello del kernel, prendendo i tuoi parametri insieme ad esso.

Un'altra prova che le cose qui sono un po 'strane è che non esiste sempre un elenco di parametri rigoroso per le chiamate di sistema: open(2), ad esempio, può accettare 2 o 3 parametri. Ciò significa che open(2) è sovraccarico , una caratteristica di C++, non di C, tuttavia l'interfaccia di syscall è compatibile con C. (Questa non è la stessa cosa di C's caratteristica varargs , che consente a una singola funzione di accettare un numero variabile di argomenti.)

Per rispondere alla tua prima domanda, non esiste un singolo file in cui esiste mkdir(). Linux supporta molti file system diversi e ognuno ha la propria implementazione dell'operazione "mkdir". Il livello di astrazione che consente al kernel di nascondere tutto ciò che si nasconde dietro una singola chiamata di sistema è chiamato VFS . Quindi, probabilmente vuoi iniziare a scavare in fs/namei.c, Con vfs_mkdir(). Le attuali implementazioni del codice di modifica del file system di basso livello sono altrove. Ad esempio, l'implementazione ext4 si chiama ext4_mkdir(), definita in fs/ext4/namei.c .

Per quanto riguarda la tua seconda domanda, sì, ci sono schemi per tutto questo, ma non una singola regola. Ciò di cui hai effettivamente bisogno è una comprensione abbastanza ampia di come funziona il kernel per capire dove dovresti cercare una particolare chiamata di sistema. Non tutte le chiamate di sistema coinvolgono VFS, quindi le loro catene di chiamate sul lato kernel non iniziano tutte in fs/namei.c. mmap(2), ad esempio, inizia in mm/mmap.c , perché fa parte del sottosistema di gestione della memoria ("mm") del kernel.

Ti consiglio di ottenere una copia di " nderstanding the Linux Kernel " di Bovet e Cesati.

388
Warren Young

Questo probabilmente non risponde direttamente alla tua domanda, ma ho trovato strace davvero interessante quando provo a capire le chiamate di sistema sottostanti, in azione, fatte anche per i comandi Shell più semplici. per esempio.

strace -o trace.txt mkdir mynewdir

Il sistema richiede il comando mkdir mynewdir verrà scaricato su trace.txt per il tuo piacere di visione.

86
Banjer

Un buon posto per leggere l'origine del kernel Linux è Riferimento incrociato di Linux (LXR) ¹. Le ricerche restituiscono corrispondenze digitate (prototipi di funzioni, dichiarazioni di variabili, ecc.) Oltre ai risultati della ricerca di testo libero, quindi è più semplice di un semplice grep (e anche più veloce).

LXR non espande le definizioni del preprocessore. Le chiamate di sistema hanno il loro nome alterato dal preprocessore in tutto il luogo. Tuttavia, la maggior parte (tutte?) Delle chiamate di sistema sono definite con uno dei SYSCALL_DEFINEx famiglie di macro. Poiché mkdir accetta due argomenti, una ricerca di SYSCALL_DEFINE2(mkdir porta alla dichiarazione di mkdir syscall :

SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
{
    return sys_mkdirat(AT_FDCWD, pathname, mode);
}

ok, sys_mkdirat significa che è la _ syscall mkdirat, quindi facendo clic su di essa ti porta solo alla dichiarazione in include/linux/syscalls.h, ma la definizione è appena sopra.

Il lavoro principale di mkdirat è chiamare vfs_mkdir (VFS è il livello del filesystem generico). Fare clic su che mostra due risultati di ricerca: la dichiarazione in include/linux/fs.h e la definizione alcune righe sopra. Il lavoro principale di vfs_mkdir è chiamare l'implementazione specifica del filesystem: dir->i_op->mkdir. Per scoprire come viene implementato this, è necessario passare all'implementazione del singolo filesystem e non esiste una regola rigida: potrebbe persino essere un modulo al di fuori dell'albero del kernel.

¹ LXR è un programma di indicizzazione. Esistono diversi siti Web che forniscono un'interfaccia a LXR, con set leggermente diversi di versioni note e interfacce Web leggermente diverse. Tendono ad andare e venire, quindi se quello a cui sei abituato non è disponibile, fai una ricerca sul web per "riferimenti incrociati Linux" per trovarne un altro.

Le chiamate di sistema sono generalmente racchiuse nella macro SYSCALL_DEFINEx(), motivo per cui un semplice grep non le trova:

fs/namei.c:SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)

Il nome della funzione finale dopo l'espansione della macro finisce per essere sys_mkdir. La macro SYSCALL_DEFINEx() aggiunge elementi come il codice di traccia che ogni definizione di syscall deve avere.

22
stefanha

Nota: il file .h non define la funzione. È dichiarato in quel file .h e definito (implementato) altrove. Ciò consente al compilatore di includere informazioni sulla firma della funzione (prototipo) per consentire il controllo del tipo di argomenti e far corrispondere i tipi restituiti a qualsiasi contesto chiamante nel codice.

In generale, i file .h (header) in C sono usati per dichiarare funzioni e definire macro.

mkdir in particolare è una chiamata di sistema. Potrebbe esserci un wrapper GNU libc attorno a quella chiamata di sistema (quasi certamente lo è, in effetti). La vera implementazione del kernel di mkdir può essere trovata cercando i sorgenti del kernel e le chiamate di sistema in particolare.

Si noti che ci sarà anche un'implementazione di una sorta di codice di creazione di directory per ciascun filesystem. Il livello VFS (virtual filesystem) fornisce un'API comune a cui può chiamare il livello di chiamata di sistema. Ogni filesystem deve registrare le funzioni per cui deve richiamare il layer VFS. Ciò consente a diversi filesystem di implementare la propria semantica per come sono strutturate le directory (ad esempio se sono archiviate usando una sorta di schema di hashing per rendere più efficiente la ricerca di voci specifiche). Ne parlo perché probabilmente si inciampano su queste funzioni di creazione di directory specifiche del filesystem se si sta cercando l'albero dei sorgenti del kernel Linux.

17
Jim Dennis

Nessuna delle implementazioni che hai trovato corrisponde al prototipo in sys/stat.h Forse la ricerca di un'istruzione include con questo file di intestazione avrebbe più successo?

8
greg0ire

Qui ci sono un paio di post sul blog davvero fantastici che descrivono varie tecniche per cercare il codice sorgente del kernel di basso livello.

6
An̲̳̳drew