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 mkdir
didefinisikan 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
- File mana yang memiliki
mkdir
implementasi? - 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 .
linux-kernel
source
system-calls
Navaneeth KN
sumber
sumber
Jawaban:
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.h
bawah direktori sumber kernel Anda, Anda menemukan ini:Kemudian di
/usr/include/asm*/unistd.h
, Anda menemukan ini: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 berartiopen(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 difs/namei.c
, denganvfs_mkdir()
. Implementasi aktual dari kode modifikasi sistem file tingkat rendah ada di tempat lain. Misalnya, implementasi ext4 disebutext4_mkdir()
, didefinisikan dalamfs/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, dimulaimm/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.
sumber
Documentation
subdirektori dari source tree untuk kernel yang saya kerjakan....
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.Ini mungkin tidak menjawab pertanyaan Anda secara langsung, tetapi saya merasa
strace
sangat keren ketika mencoba memahami panggilan sistem yang mendasarinya, dalam tindakan, yang dibuat untuk perintah shell yang paling sederhana sekalipun. misalnyaPanggilan sistem untuk perintah
mkdir mynewdir
akan dibuang ke trace.txt untuk kesenangan Anda.sumber
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_DEFINEx
keluarga makro. Karenamkdir
mengambil dua argumen, pencarianSYSCALL_DEFINE2(mkdir
mengarah ke deklarasimkdir
syscall :ok,
sys_mkdirat
berarti itumkdirat
syscall, jadi mengkliknya hanya akan membawa Anda ke deklarasiinclude/linux/syscalls.h
, tetapi definisinya tepat di atas.Tugas utama
mkdirat
adalah memanggilvfs_mkdir
(VFS adalah lapisan sistem berkas generik). Menyukai yang menunjukkan dua hasil pencarian: deklarasi diinclude/linux/fs.h
, dan definisi beberapa baris di atas. Tugas utamavfs_mkdir
adalah 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.
sumber
Panggilan sistem biasanya dibungkus dalam
SYSCALL_DEFINEx()
makro, itulah sebabnya sederhanagrep
tidak menemukannya:Nama fungsi akhir setelah makro diperluas akhirnya menjadi
sys_mkdir
. TheSYSCALL_DEFINEx()
makro menambahkan hal boilerplate seperti kode yang setiap definisi syscall perlu memiliki tracing.sumber
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.
mkdir
khususnya adalah panggilan sistem. Mungkin ada pembungkus libc GNU di sekitar panggilan sistem itu (hampir pasti, pada kenyataannya). Implementasi kernel sejatimkdir
dapat 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.
sumber
Tidak ada implementasi yang Anda temukan cocok dengan prototipe di sys / stat.h Mungkin mencari pernyataan sertakan dengan file header ini akan lebih berhasil?
sumber
Berikut adalah beberapa posting blog yang sangat bagus yang menggambarkan berbagai teknik untuk memburu kode sumber kernel tingkat rendah.
sumber