Mengapa ada kebijakan kernel Linux untuk tidak pernah merusak ruang pengguna?

38

Saya mulai memikirkan masalah ini dalam konteks etiket pada Linux Mailing list Kernel. Sebagai proyek perangkat lunak bebas yang paling dikenal dan paling sukses di dunia dan paling penting, kernel Linux mendapat banyak tekanan. Dan pendiri dan pemimpin proyek, Linus Torvalds, jelas tidak perlu diperkenalkan di sini.

Linus sesekali menarik kontroversi dengan kobaran api pada LKML. Nyala api ini sering, menurut pengakuannya sendiri, harus dilakukan dengan memecahkan ruang pengguna. Yang membawa saya ke pertanyaan saya.

Bisakah saya memiliki perspektif historis tentang mengapa memecah ruang pengguna adalah hal yang sangat buruk? Seperti yang saya pahami, memecah ruang pengguna akan membutuhkan perbaikan pada level aplikasi, tetapi apakah ini hal yang buruk, jika meningkatkan kode kernel?

Seperti yang saya pahami, kebijakan Linus menyatakan bahwa tidak melanggar ruang pengguna mengalahkan segala sesuatu yang lain, termasuk kualitas kode. Mengapa ini sangat penting, dan apa pro dan kontra dari kebijakan semacam itu?

(Jelas ada beberapa kontra terhadap kebijakan semacam itu, yang diterapkan secara konsisten, karena Linus kadang-kadang memiliki "ketidaksepakatan" dengan para letnan topnya tentang LKML tentang topik ini. Sejauh yang saya tahu, ia selalu berhasil dalam masalah ini.)

Faheem Mitha
sumber
1
Anda salah mengeja nama Linus di bagian pendahuluan.
Ismael Miguel
Itu bukan saya yang pasti, tetapi saya lupa untuk memilih dan memberikan suara saya sekarang.
Ismael Miguel
1
Terkait: stackoverflow.com/q/25954270/350713
Faheem Mitha

Jawaban:

38

Alasannya bukan alasan historis tetapi alasan praktis. Ada banyak banyak banyak program yang berjalan di atas kernel Linux; jika antarmuka kernel merusak program-program itu maka semua orang perlu memutakhirkan program-program itu.

Sekarang memang benar bahwa sebagian besar program sebenarnya tidak bergantung pada antarmuka kernel secara langsung ( panggilan sistem ), tetapi hanya pada antarmuka perpustakaan standar C ( bungkus C di sekitar panggilan sistem). Oh, tapi perpustakaan standar apa? Glibc? uClibC? Dietlibc? Bionik? Musl? dll.

Tetapi ada juga banyak program yang mengimplementasikan layanan spesifik OS dan bergantung pada antarmuka kernel yang tidak diekspos oleh pustaka standar. (Di Linux, banyak di antaranya ditawarkan melalui /procdan /sys.)

Dan kemudian ada binari yang dikompilasi secara statis. Jika upgrade kernel merusak salah satunya, satu-satunya solusi adalah mengkompilasi ulang. Jika Anda memiliki sumber: Linux juga mendukung perangkat lunak berpemilik.

Bahkan ketika sumber tersedia, mengumpulkan semua itu bisa menyebalkan. Terutama ketika Anda memutakhirkan kernel Anda untuk memperbaiki bug dengan perangkat keras Anda. Orang-orang sering memutakhirkan kernel mereka secara independen dari sisa sistem mereka karena mereka memerlukan dukungan perangkat keras. Dalam kata - kata Linus Torvalds :

Melanggar program pengguna tidak dapat diterima. (...) Kami tahu bahwa orang-orang menggunakan binari lama selama bertahun-tahun, dan membuat rilis baru tidak berarti Anda bisa membuangnya. Anda bisa mempercayai kami.

Dia juga menjelaskan bahwa salah satu alasan untuk membuat ini aturan yang kuat adalah untuk menghindari ketergantungan di mana Anda tidak hanya harus memutakhirkan program lain untuk mendapatkan beberapa kernel yang lebih baru untuk bekerja, tetapi juga harus memutakhirkan program lain, dan yang lain, dan yang lain , karena semuanya tergantung pada versi segalanya.

Ini agak ok untuk memiliki didefinisikan dengan baik ketergantungan satu arah. Menyedihkan, tapi terkadang tak terhindarkan. (...) Yang BUKAN ok adalah memiliki ketergantungan dua arah. Jika kode ruang-pengguna HAL tergantung pada kernel baru, tidak apa-apa, meskipun saya menduga pengguna berharap bahwa itu bukan "kernel minggu ini", tetapi lebih merupakan "kernel beberapa bulan terakhir".

Tetapi jika Anda memiliki ketergantungan DUA-CARA, Anda kacau. Itu berarti bahwa Anda harus memutakhirkan di langkah-kunci, dan itu TIDAK DITERIMA. Ini mengerikan bagi pengguna, tetapi yang lebih penting, mengerikan bagi pengembang, karena itu berarti Anda tidak dapat mengatakan "bug terjadi" dan melakukan hal-hal seperti mencoba mempersempitnya dengan dua atau sejenisnya.

Di userspace, saling ketergantungan itu biasanya diselesaikan dengan menjaga versi perpustakaan yang berbeda di sekitar; tetapi Anda hanya bisa menjalankan satu kernel, jadi itu harus mendukung semua orang yang mungkin ingin melakukannya.

Secara resmi ,

kompatibilitas mundur untuk [panggilan sistem dinyatakan stabil] akan dijamin selama minimal 2 tahun.

Namun dalam praktiknya,

Sebagian besar antarmuka (seperti syscalls) diharapkan tidak pernah berubah dan selalu tersedia.

Apa yang lebih sering berubah adalah antarmuka yang hanya dimaksudkan untuk digunakan oleh program yang terkait dengan perangkat keras, di /sys. ( /proc, di sisi lain, yang sejak diperkenalkannya /systelah dicadangkan untuk layanan yang tidak terkait dengan perangkat keras, hampir tidak pernah rusak dengan cara yang tidak kompatibel.)

Singkatnya,

melanggar ruang pengguna akan membutuhkan perbaikan pada level aplikasi

dan itu buruk karena hanya ada satu kernel, yang ingin ditingkatkan orang secara terpisah dari sisa sistem mereka, tetapi ada banyak banyak aplikasi di luar sana dengan saling ketergantungan yang kompleks. Lebih mudah untuk menjaga agar kernel stabil agar ribuan aplikasi tetap mutakhir di jutaan pengaturan yang berbeda.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1
Terima kasih atas jawabannya. Jadi, antarmuka yang dinyatakan stabil adalah superset dari panggilan sistem POSIX? Pertanyaan saya tentang sejarah adalah bagaimana praktik ini berkembang. Agaknya versi asli dari kernel Linux tidak khawatir tentang kerusakan ruang pengguna, setidaknya pada awalnya.
Faheem Mitha
3
@FaheemMitha Ya, sudah, sejak 1991 . Saya tidak berpikir pendekatan Linus berevolusi, itu selalu "antarmuka untuk aplikasi normal tidak berubah, antarmuka untuk perangkat lunak yang sangat kuat terkait dengan perubahan kernel sangat jarang".
Gilles 'SO- stop being evil'
24

Dalam setiap sistem yang saling tergantung pada dasarnya ada dua pilihan. Abstraksi dan integrasi. (Saya sengaja tidak menggunakan istilah teknis). Dengan Abstraksi, Anda mengatakan bahwa ketika Anda membuat panggilan ke API itu, sementara kode di belakang API dapat berubah, hasilnya akan selalu sama. Sebagai contoh ketika kita memanggil fs.open()kita tidak peduli apakah itu drive jaringan, SSD atau hard drive, kita akan selalu mendapatkan deskriptor file terbuka yang dapat kita lakukan. Dengan "integrasi" tujuannya adalah untuk menyediakan cara "terbaik" untuk melakukan sesuatu, bahkan jika caranya berubah. Misalnya, membuka file mungkin berbeda untuk berbagi jaringan daripada untuk file pada disk. Kedua cara digunakan cukup luas di desktop Linux modern.

Dari sudut pandang pengembang, pertanyaannya adalah "bekerja dengan versi apa pun" atau "bekerja dengan versi tertentu". Contoh yang bagus untuk hal ini adalah OpenGL. Sebagian besar game diatur untuk bekerja dengan versi OpenGL tertentu. Tidak masalah jika Anda mengkompilasi dari sumber. Jika gim ini ditulis menggunakan OpenGL 1.1 dan Anda mencoba menjalankannya pada 3.x, Anda tidak akan bersenang-senang. Di ujung lain spektrum, beberapa panggilan, diharapkan berfungsi apa pun yang terjadi. Sebagai contoh, saya ingin menelepon fs.open()Saya tidak ingin peduli dengan versi kernel apa saya. Saya hanya ingin deskriptor file.

Ada manfaat untuk setiap cara. Integrasi menyediakan fitur "yang lebih baru" dengan biaya kompatibilitas ke belakang. Sementara abstraksi memberikan stabilitas atas panggilan "baru". Meskipun penting untuk dicatat ini masalah prioritas, bukan kemungkinan.

Dari sudut pandang komunal, tanpa alasan yang sangat bagus, abstraksi selalu lebih baik dalam sistem yang kompleks. Sebagai contoh, bayangkan jika fs.open()bekerja secara berbeda tergantung pada versi kernel. Kemudian pustaka interaksi sistem file sederhana perlu mempertahankan beberapa ratus metode "file terbuka" yang berbeda (atau mungkin blok). Ketika versi kernel baru keluar, Anda tidak akan dapat "meningkatkan", Anda harus menguji setiap bagian dari perangkat lunak yang Anda gunakan. Kernel 6.2.2 (palsu) dapat merusak editor teks Anda.

Untuk beberapa contoh dunia nyata OSX cenderung tidak peduli tentang melanggar User Space. Mereka bertujuan untuk "integrasi" lebih dari "abstraksi" lebih sering. Dan pada setiap pembaruan OS utama, banyak hal rusak. Itu bukan untuk mengatakan satu cara lebih baik dari yang lain. Ini pilihan dan keputusan desain.

Yang paling penting, sistem ekologi Linux dipenuhi dengan proyek opensource yang luar biasa, di mana orang atau kelompok bekerja pada proyek di waktu luang mereka, atau karena alat ini berguna. Dengan pemikiran itu, yang kedua berhenti menjadi menyenangkan dan mulai menjadi PIA, para pengembang itu akan pergi ke tempat lain.

Misalnya, saya mengirim tambalan ke BuildNotify.py. Bukan karena saya altruistik, tetapi karena saya menggunakan alat ini, dan saya menginginkan fitur. Itu mudah, jadi di sini, punya tambalan. Jika rumit, atau rumit, saya tidak akan menggunakan BuildNotify.pydan saya akan menemukan sesuatu yang lain. Jika setiap kali pembaruan kernel keluar, editor teks saya rusak, saya hanya akan menggunakan OS yang berbeda. Kontribusi saya kepada komunitas (sekecil apa pun) tidak akan berlanjut atau ada, dan seterusnya.

Jadi, keputusan desain dibuat untuk panggilan sistem abstrak, sehingga ketika saya melakukannya fs.open()hanya berfungsi. Itu berarti mempertahankan fs.openlama setelah fs.open2()mendapatkan popularitas.

Secara historis, ini adalah tujuan dari sistem POSIX secara umum. "Ini satu set panggilan dan nilai pengembalian yang diharapkan, kamu tahu tengahnya." Lagi untuk alasan portabilitas. Mengapa Linus memilih untuk menggunakan metodologi itu adalah internal otaknya, dan Anda harus memintanya untuk tahu persis mengapa. Namun jika saya, saya akan memilih abstraksi daripada integrasi pada sistem yang kompleks.

kapas
sumber
1
API untuk userspace, 'syscall' API, didefinisikan dengan baik (terutama subset POSIX) dan stabil, karena menghapus bagian mana pun akan merusak perangkat lunak yang mungkin dipasang orang. Apa yang tidak dimilikinya adalah API driver yang stabil .
pjc50
4
@FaheemMitha, ini sebaliknya. Pengembang kernel bebas untuk memutus API driver kapan saja mereka inginkan, selama mereka memperbaiki semua driver di-kernel sebelum rilis berikutnya. Ini melanggar API userspace, atau bahkan melakukan hal-hal non-API yang dapat menghancurkan userspace, yang menghasilkan reaksi epik dari Linus.
Tandai
4
Misalnya, jika seseorang memutuskan untuk mengubahnya dengan mengembalikan kode kesalahan yang berbeda dari ioctl () dalam beberapa keadaan: lkml.org/lkml/2012/12/23/75 (berisi sumpah serapah dan serangan pribadi pada pengembang yang bertanggung jawab). Patch itu ditolak karena akan merusak PulseAudio, dan karenanya semua audio pada sistem GNOME.
pjc50
1
@FaheemMitha, pada dasarnya, def add (a, b); kembalikan a + b; end --- def add (a, b); c = a + b; kembali c; end --- def add (a, b); c = a + b +10; return c - 10; end - adalah semua implementasi add yang "sama". Yang membuatnya kesal adalah ketika orang menambahkan def (a, b); return (a + b) * -1; Pada intinya, mengubah bagaimana hal-hal "internal" ke pekerjaan kernel ok. Mengubah apa yang dikembalikan ke panggilan API yang ditentukan dan "publik" tidak. Ada dua jenis panggilan API "pribadi" dan "publik". Dia merasa bahwa panggilan API publik tidak boleh berubah tanpa alasan yang kuat.
coteyr
3
Contoh bukan kode; Anda pergi ke toko, Anda membeli 87 Oktana gas. Anda, sebagai konsumen tidak "peduli" dari mana gas itu berasal, atau bagaimana gas itu diproses. Anda hanya peduli dengan gas Anda. Jika gas melewati proses pemurnian yang berbeda, Anda tidak peduli. Tentu proses pemurnian bisa berubah. Bahkan ada berbagai sumber minyak. Tapi yang Anda pedulikan adalah mendapatkan 87 Oktane gas. Jadi posisinya, adalah mengubah sumber, mengubah kilang, mengubah apa pun, selama apa yang keluar di pompa adalah 87 gas oktan. Semua hal "di balik layar" tidak masalah. Selama ada 87 gas oktan.
coteyr
8

Ini keputusan dan pilihan desain. Linus ingin dapat menjamin kepada pengembang ruang-pengguna bahwa, kecuali dalam keadaan yang sangat jarang dan luar biasa (misalnya terkait keamanan), perubahan pada kernel tidak akan merusak aplikasi mereka.

Pronya adalah bahwa pengguna devs tidak akan menemukan kode mereka tiba-tiba melanggar kernel baru karena alasan sewenang-wenang dan berubah-ubah.

Kontra adalah bahwa kernel harus menyimpan kode lama dan syscalls lama dll sekitar selamanya (atau, setidaknya, lama melewati tanggal penggunaan-oleh).

cas
sumber
Terima kasih atas balasannya. Apakah Anda mengetahui sejarah bagaimana keputusan ini berkembang? Saya menyadari proyek yang mengambil perspektif yang agak berbeda. Misalnya proyek Mercurial tidak memiliki API tetap, dan dapat dan memecah kode yang bergantung padanya.
Faheem Mitha
Tidak, maaf, saya tidak dapat mengingat bagaimana itu terjadi. Anda bisa mengirim email ke Linus atau LKML dan bertanya kepadanya.
cas
2
Mercurial bukan OS. Seluruh poin dari OS adalah untuk mengaktifkan jalannya perangkat lunak lain di atasnya, dan menghancurkan perangkat lunak lain itu sangat tidak populer. Sebagai perbandingan, Windows juga mempertahankan kompatibilitas ke belakang untuk waktu yang sangat lama; Kode Windows 16-bit baru-baru ini sudah usang.
pjc50
@ pjc50 Memang benar bahwa Mercurial bukan OS, tapi terlepas, ada adalah perangkat lunak lain, bahkan jika hanya script, yang bergantung padanya. Dan berpotensi rusak oleh perubahan.
Faheem Mitha