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


375

Sto cercando di capire come funziona una funzione, diciamo mkdir, guardando il sorgente 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' mkdirimplementazione?
  2. Con una definizione di funzione come quella 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 .


2
A proposito, dai un'occhiata a questo: voinici.ceata.org/~tct/resurse/utlk.pdf
Tom Brito,

Risposte:


386

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 inline 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.

Nel include/linux/syscalls.hsotto la directory dei sorgenti del kernel, si trova questo:

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

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

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Questo codice dice che 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 per assemblaggio in linea che ho menzionato sopra lo usa per effettuare la transizione dallo spazio utente a quello del kernel, prendendo i tuoi parametri insieme ad esso.

Un'altra prova che le cose sono un po 'strane qui è che non c'è sempre un rigido elenco di parametri 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 C, tuttavia l'interfaccia di syscall è compatibile con C. (Questa non è la stessa cosa della funzione varargs di C , che consente a una singola funzione di accettare un numero variabile di argomenti.)

Per rispondere alla tua prima domanda, non esiste un singolo file dove mkdir()esiste. 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 fs/namei.c, con vfs_mkdir(). Le attuali implementazioni del codice di modifica del file system di basso livello sono altrove. Ad esempio, viene chiamata l'implementazione ext4 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 fs/namei.c. mmap(2), ad esempio, inizia mm/mmap.cperché fa parte del sottosistema di gestione della memoria ("mm") del kernel.

Ti consiglio di ottenere una copia di " Capire il kernel Linux " di Bovet e Cesati.


Ottima risposta Un punto sul libro che citi "Comprensione del kernel Linux". Non ce l'ho, ma dalla data di uscita (2000) e TOC (sul sito di oreilly) mi sembrano circa 2,2 kernel più alcune intuizioni da 2,4 kernel (ma mi sbaglio). La mia domanda è: esiste un libro equivalente che copre 2.6 kernel interni? (o ancora meglio che copre 2.2, 2.4 e 2.6)?
DavAlPi

2
@DavAlPi: Per quanto ne so, Bovet & Cesati è ancora il miglior libro singolo su questo argomento. Quando ho bisogno di integrarlo con altro materiale aggiornato, vado a scavare nella Documentationsottodirectory dell'albero dei sorgenti per il kernel con cui sto lavorando.
Warren Young,

1
In effetti open (2) è una funzione varargs. Ci sono solo due modi per chiamarlo, quindi la manpage lo documenta in questo modo, il prototipo reale ha ...in sé una funzione varargs. Naturalmente, questo è implementato a livello di libc. Può passare 0 o un valore di immondizia all'ABI del kernel quando non viene utilizzato il terzo parametro.
Casuale 832

"È qualcosa che non devi capire". Il mondo sarebbe un posto migliore se questo tipo di frase non fosse presente da nessuna parte sulla rete di stackexchange.
Petr

84

Questo probabilmente non risponde direttamente alla tua domanda, ma ho scoperto straceche è davvero bello quando provo a capire le chiamate di sistema sottostanti, in azione, fatte anche per i comandi di shell più semplici. per esempio

strace -o trace.txt mkdir mynewdir

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


5
+1 trucco accurato! Non lo avevo mai usato prima
David Oneill il

3
Meglio ancora, crea il file di output trace.strace e aprilo in VIM. VIM lo evidenzierà, rendendolo molto più facile da leggere.
Marcin,

55

Un buon posto per leggere l'origine del kernel Linux è il riferimento incrociato 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 una delle SYSCALL_DEFINExfamiglie di macro. Poiché mkdiraccetta due argomenti, una ricerca di SYSCALL_DEFINE2(mkdirporta alla dichiarazione della mkdirsyscall :

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

ok, sys_mkdiratsignifica che è la mkdiratsyscall, quindi fare clic su di essa 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 questo mostra due risultati di ricerca: la dichiarazione in include/linux/fs.he la definizione poche righe sopra. Il compito principale del vfs_mkdirè quello di chiamare l'implementazione specifica-file system: dir->i_op->mkdir. Per trovare il modo questo è implementata, è necessario attivare l'attuazione del filesystem individuale, e non c'è nessuna regola hard-and-fast - potrebbe anche essere un modulo al di fuori 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 su Linux" per trovarne un altro.


Questo è un diavolo di una risorsa. Bella risposta.
Stabledog,

"Errore interno del server" nel collegamento di linux.no .
Fredrick Gauss,

@FredrickGauss Per un po 'lxr.linux.no è stata la migliore interfaccia per LXR ma ha avuto frequenti downtime. Ora penso che sia andato per sempre. Ho sostituito il primo collegamento a un'altra interfaccia LXR.
Gilles

21

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

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

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


17

Nota: il file .h non definisce 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.

mkdirin particolare è una chiamata di sistema. Potrebbe esserci un wrapper libc GNU attorno a quella chiamata di sistema (quasi certamente lo è, in effetti). La vera implementazione del kernel di mkdirpuò 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.


8

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?


1
L'implementazione (come descritto in sys / stat.h) è il business di userland e libc. Le cose interne al kernel (come è fatto veramente ) sono affari interni al kernel. Per tutti gli hacker del kernel, la funzione interna potrebbe essere chiamata xyzzy e prendere 5 parametri. È compito di libc prendere la chiamata di userland, tradurla in qualsiasi incantesimo del kernel, spedirla e raccogliere tutti i risultati.
vonbrand,

6

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.


12
Ti preghiamo di non pubblicare solo collegamenti a blog o forum, di riassumere i loro contenuti in modo che i lettori possano vedere di cosa si tratta e di lasciare loro qualcosa se i siti scompaiono. Inoltre, il tuo primo link riguarda libc, che è fuori tema per questa domanda.
Gilles,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.