Bagaimana saya bisa menemukan implementasi panggilan sistem kernel Linux?

375

Saya mencoba memahami bagaimana fungsi, katakanlah mkdir, bekerja dengan melihat sumber kernel. Ini adalah upaya untuk memahami internal kernel dan bernavigasi di antara berbagai fungsi. Saya tahu mkdirdidefinisikan dalam sys/stat.h. Saya menemukan prototipe:

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

Sekarang saya perlu melihat di mana file C fungsi ini diimplementasikan. Dari direktori sumber, saya mencoba

ack "int mkdir"

yang ditampilkan

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);

Tapi tidak ada yang cocok dengan definisi di sys/stat.h.

Pertanyaan

  1. File mana yang memiliki mkdirimplementasi?
  2. Dengan definisi fungsi seperti di atas, bagaimana saya bisa mengetahui file mana yang memiliki implementasi? Apakah ada pola yang diikuti kernel dalam mendefinisikan dan mengimplementasikan metode?

CATATAN: Saya menggunakan kernel 2.6.36-rc1 .

Navaneeth KN
sumber
2
Ngomong-ngomong, periksa ini: voinici.ceata.org/~tct/resurse/utlk.pdf
Tom Brito

Jawaban:

386

Panggilan sistem tidak ditangani seperti panggilan fungsi biasa. Dibutuhkan kode khusus untuk melakukan transisi dari ruang pengguna ke ruang kernel, pada dasarnya sedikit kode rakitan inline yang disuntikkan ke program Anda di situs panggilan. Kode samping kernel yang "menangkap" panggilan sistem juga merupakan hal-hal tingkat rendah yang mungkin tidak perlu Anda pahami secara mendalam, setidaknya pada awalnya.

Di include/linux/syscalls.hbawah direktori sumber kernel Anda, Anda menemukan ini:

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

Kemudian di /usr/include/asm*/unistd.h, Anda menemukan ini:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Kode ini katakan mkdir(2)adalah system call # 83. Dengan kata lain, panggilan sistem dipanggil dengan nomor, bukan dengan alamat seperti panggilan fungsi normal dalam program Anda sendiri atau ke fungsi di perpustakaan yang ditautkan dengan program Anda. Kode lem inline assembly yang saya sebutkan di atas menggunakan ini untuk melakukan transisi dari ruang pengguna ke kernel, dengan mengambil parameter Anda.

Sedikit bukti lain yang agak aneh di sini adalah tidak selalu ada daftar parameter yang ketat untuk panggilan sistem:, open(2)misalnya, dapat mengambil 2 atau 3 parameter. Itu berarti open(2)adalah kelebihan beban , fitur C ++, bukan C, namun antarmuka syscall adalah C-kompatibel. (Ini bukan hal yang sama dengan fitur varargs C , yang memungkinkan fungsi tunggal untuk mengambil sejumlah variabel argumen.)

Untuk menjawab pertanyaan pertama Anda, tidak ada file tunggal di mana mkdir()ada. Linux mendukung banyak sistem file yang berbeda dan masing-masing memiliki implementasi sendiri operasi "mkdir". Lapisan abstraksi yang memungkinkan kernel menyembunyikan semua yang ada di balik panggilan sistem tunggal disebut VFS . Jadi, Anda mungkin ingin mulai menggali di fs/namei.c, dengan vfs_mkdir(). Implementasi aktual dari kode modifikasi sistem file tingkat rendah ada di tempat lain. Misalnya, implementasi ext4 disebut ext4_mkdir(), didefinisikan dalam fs/ext4/namei.c.

Adapun pertanyaan kedua Anda, ya ada pola untuk semua ini, tetapi tidak ada aturan tunggal. Apa yang sebenarnya Anda butuhkan adalah pemahaman yang cukup luas tentang cara kerja kernel untuk mencari tahu di mana Anda harus mencari panggilan sistem tertentu. Tidak semua panggilan sistem melibatkan VFS, jadi rantai panggilan sisi-kernel tidak semuanya dimulai fs/namei.c. mmap(2), misalnya, dimulai mm/mmap.c, karena ini adalah bagian dari subsistem manajemen memori ("mm") dari kernel.

Saya sarankan Anda mendapatkan salinan " Memahami Kernel Linux " oleh Bovet dan Cesati.

Warren Young
sumber
Jawaban yang sangat bagus Satu poin tentang buku yang Anda sebutkan, "Memahami Kernel Linux". Saya tidak memilikinya, tetapi dari tanggal rilis (2000) dan TOC (di situs oreilly) bagi saya adalah sekitar 2,2 kernel ditambah beberapa wawasan dari 2,4 kernel (tapi saya salah). Pertanyaan saya adalah: ada buku yang setara yang mencakup 2,6 kernel internal? (atau lebih baik lagi yang mencakup 2.2, 2.4 dan 2.6)?
DavAlPi
2
@DavAlPi: Sejauh yang saya ketahui, Bovet & Cesati masih menjadi buku tunggal terbaik tentang topik ini. Ketika saya perlu menambahkannya dengan lebih banyak materi terkini, saya menggali di Documentationsubdirektori dari source tree untuk kernel yang saya kerjakan.
Warren Young
1
Sebenarnya open (2) adalah fungsi varargs. Hanya ada dua cara untuk menyebutnya, sehingga manual mendokumentasikannya dengan cara ini, prototipe yang sebenarnya ada ...di dalamnya sebagai fungsi varargs. Tentu saja, ini diterapkan pada level libc. Ini bisa melewati 0 atau nilai sampah ke kernel ABI ketika parameter ketiga tidak digunakan.
Random832
"Itu sesuatu yang tidak perlu kau mengerti". Dunia akan menjadi tempat yang lebih baik jika kalimat semacam ini tidak ditemukan di jaringan stackexchange.
Petr
84

Ini mungkin tidak menjawab pertanyaan Anda secara langsung, tetapi saya merasa stracesangat keren ketika mencoba memahami panggilan sistem yang mendasarinya, dalam tindakan, yang dibuat untuk perintah shell yang paling sederhana sekalipun. misalnya

strace -o trace.txt mkdir mynewdir

Panggilan sistem untuk perintah mkdir mynewdirakan dibuang ke trace.txt untuk kesenangan Anda.

Banjer
sumber
5
+1 Trik rapi! Saya tidak akan menggunakannya sebelumnya
David Oneill
3
Lebih baik lagi, buat file output trace.strace, dan buka di VIM. VIM akan menyorotnya, membuatnya lebih mudah dibaca.
Marcin
55

Tempat yang baik untuk membaca sumber kernel Linux adalah Linux cross-reference (LXR) ¹. Pencarian mengembalikan kecocokan yang diketik (prototipe fungsi, deklarasi variabel, dll.) Selain hasil pencarian teks gratis, jadi lebih mudah daripada hanya grep (dan lebih cepat juga).

LXR tidak memperluas definisi preprosesor. Panggilan sistem memiliki nama mereka hancur oleh preprosesor di semua tempat. Namun, sebagian besar (semua?) Panggilan sistem didefinisikan dengan salah satu SYSCALL_DEFINExkeluarga makro. Karena mkdirmengambil dua argumen, pencarian SYSCALL_DEFINE2(mkdirmengarah ke deklarasi mkdirsyscall :

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

ok, sys_mkdiratberarti itu mkdiratsyscall, jadi mengkliknya hanya akan membawa Anda ke deklarasi include/linux/syscalls.h, tetapi definisinya tepat di atas.

Tugas utama mkdiratadalah memanggil vfs_mkdir(VFS adalah lapisan sistem berkas generik). Menyukai yang menunjukkan dua hasil pencarian: deklarasi di include/linux/fs.h, dan definisi beberapa baris di atas. Tugas utama vfs_mkdiradalah untuk memanggil implementasi filesystem-spesifik: dir->i_op->mkdir. Untuk mengetahui bagaimana ini diterapkan, Anda perlu beralih ke implementasi sistem file individual, dan tidak ada aturan yang sulit dan cepat - bahkan bisa menjadi modul di luar pohon kernel.

¹ LXR adalah program pengindeksan. Ada beberapa situs web yang menyediakan antarmuka untuk LXR, dengan set versi yang sedikit berbeda dan antarmuka web yang sedikit berbeda. Mereka cenderung datang dan pergi, jadi jika yang Anda gunakan tidak tersedia, lakukan pencarian web untuk "referensi silang linux" untuk menemukan yang lain.

Gilles
sumber
Itu adalah salah satu sumber daya. Jawaban yang bagus
Stabledog
"Internal Server Error" di tautan linux.no .
Fredrick Gauss
@ FredrickGauss Untuk sementara waktu lxr.linux.no itu adalah antarmuka terbaik untuk LXR tetapi sering downtime. Sekarang saya pikir itu hilang untuk selamanya. Saya mengganti tautan pertama ke antarmuka LXR lainnya.
Gilles
21

Panggilan sistem biasanya dibungkus dalam SYSCALL_DEFINEx()makro, itulah sebabnya sederhana greptidak menemukannya:

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

Nama fungsi akhir setelah makro diperluas akhirnya menjadi sys_mkdir. The SYSCALL_DEFINEx()makro menambahkan hal boilerplate seperti kode yang setiap definisi syscall perlu memiliki tracing.

stefanha
sumber
17

Catatan: file .h tidak mendefinisikan fungsi. Ini dinyatakan dalam file .h dan didefinisikan (diimplementasikan) di tempat lain. Ini memungkinkan kompiler untuk memasukkan informasi tentang tanda tangan fungsi (prototipe) untuk memungkinkan pemeriksaan jenis argumen dan mencocokkan jenis yang dikembalikan ke konteks panggilan apa pun dalam kode Anda.

Secara umum .h (header) file dalam C digunakan untuk mendeklarasikan fungsi dan mendefinisikan makro.

mkdirkhususnya adalah panggilan sistem. Mungkin ada pembungkus libc GNU di sekitar panggilan sistem itu (hampir pasti, pada kenyataannya). Implementasi kernel sejati mkdirdapat ditemukan dengan mencari sumber kernel dan panggilan sistem pada khususnya.

Perhatikan bahwa juga akan ada implementasi semacam kode pembuatan direktori untuk setiap sistem file. Lapisan VFS (sistem file virtual) menyediakan API umum yang dapat dipanggil oleh lapisan sistem panggilan. Setiap sistem file harus mendaftarkan fungsi untuk lapisan VFS untuk dipanggil. Hal ini memungkinkan berbagai sistem file untuk mengimplementasikan semantik mereka sendiri untuk bagaimana direktori disusun (misalnya jika mereka disimpan menggunakan semacam skema hashing untuk membuat pencarian entri tertentu lebih efisien). Saya menyebutkan ini karena Anda mungkin akan tersandung fungsi pembuatan direktori spesifik sistem file ini jika Anda mencari pohon kode sumber Linux.

Jim Dennis
sumber
8

Tidak ada implementasi yang Anda temukan cocok dengan prototipe di sys / stat.h Mungkin mencari pernyataan sertakan dengan file header ini akan lebih berhasil?

greg0ire
sumber
1
Implementasi (sebagaimana dijelaskan dalam sys / stat.h) adalah bisnis dari userland dan libc. Hal-hal internal kernel (bagaimana itu benar - benar dilakukan) adalah bisnis internal kernel. Untuk semua perawatan peretas kernel, fungsi internal dapat disebut xyzzy dan mengambil 5 parameter. Adalah tugas libc untuk menerima panggilan pengguna, menerjemahkannya ke dalam mantra kernel apa pun yang diperlukan, mengirimkannya dan mengumpulkan hasil apa pun.
vonbrand
6

Berikut adalah beberapa posting blog yang sangat bagus yang menggambarkan berbagai teknik untuk memburu kode sumber kernel tingkat rendah.

An̲̳̳drew
sumber
12
Tolong jangan memposting hanya tautan ke blog atau forum, meringkas konten mereka sehingga pembaca dapat melihat apa yang mereka tentang, dan untuk memiliki sesuatu yang tersisa jika situs tersebut hilang. Juga, tautan pertama Anda adalah tentang libc, yang di luar topik untuk pertanyaan ini.
Gilles