Sementara pertanyaan Stack Overflow tampaknya cukup pada awalnya, saya mengerti, dari komentar Anda, mengapa Anda mungkin masih ragu tentang ini. Bagi saya, ini persis seperti situasi kritis yang terlibat ketika dua subsistem UNIX (proses dan file) berkomunikasi.
Seperti yang Anda ketahui, sistem UNIX biasanya dibagi menjadi dua subsistem: subsistem file, dan subsistem proses. Sekarang, kecuali diinstruksikan sebaliknya melalui panggilan sistem, kernel seharusnya tidak memiliki dua subsistem ini berinteraksi satu sama lain. Namun ada satu pengecualian: memuat file yang dapat dieksekusi ke dalam wilayah teks proses . Tentu saja, orang mungkin berpendapat bahwa operasi ini juga dipicu oleh pemanggilan sistem ( execve
), tetapi ini biasanya dikenal sebagai satu - satunya kasus di mana subsistem proses membuat permintaan implisit ke subsistem file.
Karena subsistem proses secara alami tidak memiliki cara untuk menangani file (jika tidak maka tidak ada gunanya membagi semuanya menjadi dua), ia harus menggunakan apa pun yang disediakan oleh subsistem file untuk mengakses file. Ini juga berarti bahwa subsistem proses dikirimkan ke ukuran apa pun yang diambil subsistem file terkait edisi file / penghapusan. Pada titik ini, saya akan merekomendasikan membaca jawaban Gilles untuk pertanyaan U&L ini . Sisa jawaban saya didasarkan pada yang lebih umum dari Gilles ini.
Hal pertama yang harus diperhatikan adalah bahwa secara internal, file hanya dapat diakses melalui inode . Jika kernel diberikan path, langkah pertama adalah menerjemahkannya menjadi inode yang akan digunakan untuk semua operasi lainnya. Ketika suatu proses memuat sebuah executable ke dalam memori, ia melakukannya melalui inode-nya, yang telah disediakan oleh subsistem file setelah terjemahan suatu path. Inode dapat dikaitkan dengan beberapa jalur (tautan), dan program hanya dapat menghapus tautan. Untuk menghapus file dan inode-nya, userland harus menghapus semua tautan yang ada ke inode itu, dan memastikan bahwa itu benar-benar tidak digunakan. Ketika kondisi ini terpenuhi, kernel akan secara otomatis menghapus file dari disk.
Jika Anda melihat bagian pengganti yang dapat dieksekusi dari jawaban Gilles, Anda akan melihat bahwa tergantung pada bagaimana Anda mengedit / menghapus file, kernel akan bereaksi / beradaptasi secara berbeda, selalu melalui mekanisme yang diterapkan dalam subsistem file.
- Jika Anda mencoba strategi satu ( buka / truncate ke nol / tulis atau buka / tulis / truncate ke ukuran baru ), Anda akan melihat bahwa kernel tidak akan repot menangani permintaan Anda. Anda akan mendapatkan kesalahan 26: File teks sibuk (
ETXTBSY
). Tidak ada konsekuensi apa pun.
- Jika Anda mencoba strategi dua, langkah pertama adalah menghapus executable Anda. Namun, karena sedang digunakan oleh suatu proses, subsistem file akan menendang dan mencegah file (dan inode) dari yang benar - benar dihapus dari disk. Dari titik ini, satu-satunya cara untuk mengakses konten file lama adalah dengan melakukannya melalui inode-nya, yang merupakan apa yang dilakukan subsistem proses setiap kali perlu memuat data baru ke dalam bagian teks (secara internal, tidak ada gunanya menggunakan jalur, kecuali saat menerjemahkannya ke dalam inode). Meskipun Anda telah memutuskan tautanfile (menghapus semua jalurnya), proses masih dapat menggunakannya seolah-olah Anda tidak melakukan apa-apa. Membuat file baru dengan path lama tidak akan mengubah apa pun: file baru akan diberikan inode yang sama sekali baru, yang tidak diketahui oleh proses yang sedang berjalan.
Strategi 2 dan 3 juga aman untuk executable: walaupun menjalankan executable (dan perpustakaan yang dimuat secara dinamis) tidak membuka file dalam arti memiliki deskriptor file, mereka berperilaku dengan cara yang sangat mirip. Selama beberapa program menjalankan kode, file tetap di disk bahkan tanpa entri direktori.
- Strategi tiga sangat mirip karena
mv
operasi adalah satu atom. Ini mungkin akan memerlukan penggunaan rename
panggilan sistem, dan karena proses tidak dapat diinterupsi saat dalam mode kernel, tidak ada yang dapat mengganggu operasi ini sampai selesai (berhasil atau tidak). Sekali lagi, tidak ada perubahan inode file lama: yang baru dibuat, dan proses yang sudah berjalan tidak akan mengetahuinya, bahkan jika dikaitkan dengan salah satu tautan inode lama.
Dengan strategi 3, langkah memindahkan file baru ke nama yang ada menghapus entri direktori yang mengarah ke konten lama dan membuat entri direktori yang mengarah ke konten baru. Ini dilakukan dalam satu operasi atom, jadi strategi ini memiliki keuntungan besar: jika suatu proses membuka file kapan saja, ia akan melihat konten lama atau konten baru - tidak ada risiko mendapatkan konten campuran atau file tidak ada.
Mengkompilasi ulang file : ketika menggunakan gcc
(dan perilaku ini mungkin serupa untuk banyak kompiler lain), Anda menggunakan strategi 2. Anda dapat melihat bahwa dengan menjalankan strace
proses kompiler Anda:
stat("a.out", {st_mode=S_IFREG|0750, st_size=8511, ...}) = 0
unlink("a.out") = 0
open("a.out", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3
chmod("a.out", 0750) = 0
- Compiler mendeteksi bahwa file sudah ada melalui
stat
dan lstat
panggilan sistem.
- File tidak terhubung . Di sini, sementara itu tidak lagi dapat diakses melalui nama
a.out
, inode dan isinya tetap pada disk, selama mereka digunakan oleh proses yang sudah berjalan.
- File baru dibuat dan dapat dieksekusi di bawah nama
a.out
. Ini adalah inode baru, dan konten baru, yang proses yang sudah berjalan tidak peduli.
Sekarang, ketika datang ke perpustakaan bersama, perilaku yang sama akan berlaku. Selama objek perpustakaan digunakan oleh suatu proses, itu tidak akan dihapus dari disk, tidak peduli bagaimana Anda mengubah tautannya. Kapan pun sesuatu harus dimuat ke dalam memori, kernel akan melakukannya melalui inode file, dan karena itu akan mengabaikan perubahan yang Anda buat pada tautannya (seperti mengaitkannya dengan file baru).