15 poin oleh GN⁺ 2024-09-01 | 2 komentar | Bagikan ke WhatsApp
  • Saya rasa orang-orang belum cukup menyadari betapa tidak lengkapnya dokumentasi API kernel Linux, dan bagaimana Rust menyelesaikan sebagian dari masalah itu
  • Saya telah menulis abstraksi Rust untuk beberapa subsistem, dan di hampir semua kasus saya harus membaca kode sumber C untuk benar-benar memahami cara menggunakan API dengan aman
  • Hanya dari signature fungsi serta komentar dokumentasi terkait atau dokumentasi eksplisit saja, sulit untuk memahami sepenuhnya cara penggunaan API yang aman
    • apakah lock harus tetap dipegang
    • apakah argumen reference count menyerahkan referensi atau justru mengambil referensinya sendiri
    • apakah lock tetap dipegang saat callback dipanggil, atau harus diperoleh sendiri
    • apakah ada hal khusus pada callback free
    • urutan lock yang dimaksud itu seperti apa
    • apakah ada situasi khusus di mana beberapa operasi dalam kondisi tertentu boleh menggunakan lock
    • apakah argumen NULL diperbolehkan dan bagaimana penggunaan yang valid
    • apa yang terjadi pada reference count saat terjadi error
    • apakah pointer reference count yang dikembalikan sudah dinaikkan, atau hanya pinjaman implisit dari referensi argumen yang diberikan
    • apakah nilai balik selalu pointer yang valid, bisa NULL, atau bahkan bisa berupa ERR_PTR
    • apakah pointer yang dikembalikan melalui argumen tidak langsung dibersihkan menjadi NULL saat error, atau dibiarkan apa adanya
    • apakah valid mengirimkan NULL ** ketika pointer hasil tidak diperlukan
  • Terkadang kebutuhannya masuk akal, tetapi tidak didokumentasikan
    • kadang kebutuhannya terlalu fleksibel atau kompleks, sehingga saat menulis abstraksi Rust saya harus membuat keputusan subjektif untuk mempersempitnya ke cara penggunaan yang aman
    • kadang saya harus menambahkan lock tambahan di dalam abstraksi untuk menjamin keamanan
    • kadang saya harus membuat sedikit perubahan agar kode C menjadi lebih ortogonal, lebih logis, dan lebih mudah digunakan (misalnya mengekspos fungsi unlock untuk dipakai ketika lock sedang dipegang)
    • kadang locking-nya begitu halus sehingga abstraksi Rust yang aman tetap bisa ditulis, tetapi memerlukan komentar dokumentasi besar yang memperingatkan agar berhati-hati pada cara penggunaan dan urutan pelepasan demi mencegah deadlock (Rust pada dasarnya tidak mencegah deadlock)
    • kadang masalahnya tidak bisa diselesaikan kecuali kode C dibuat lebih masuk akal (seperti pada drm_sched)
  • Namun dalam kebanyakan kasus, kompromi saat menulis abstraksi Rust justru menunjukkan masalah desain pada kode C dan arah perbaikannya
    • pendekatan umumnya adalah "pertama tulis kode Rust dengan perubahan sesedikit mungkin pada kode C agar tidak memicu konflik, lalu usulkan perubahan pada kode C berdasarkan pelajaran yang didapat" (bagian kedua ini belum sempat saya kerjakan)
  • Hasilnya, dalam kebanyakan kasus, cara penggunaan yang benar bisa diketahui hanya dengan melihat API Rust
    • tidak perlu khawatir soal reference count, pointer NULL, lupa memeriksa hasil, atau melepas referensi saat error
    • tidak perlu khawatir soal penggunaan lock yang benar, lupa mengambil referensi, atau double free
    • tidak perlu bertanya-tanya tentang bagaimana nilai error return dienkodekan
    • karena jika hal-hal itu salah, kodenya tidak akan bisa dikompilasi
    • tentu API masih bisa disalahgunakan, tetapi dalam kasus terburuk hanya akan menghasilkan error return atau deadlock (deadlock mudah di-debug dengan lockdep, dan integrasi Arc<> dapat menangkap kesalahan locking yang terkait dengan free/unref)
  • Bahkan API OpenFirmware/DeviceTree yang relatif terdokumentasi dengan ketat pun, di C tetap membosankan dan mudah salah untuk mengikuti semua aturannya
    • jika melihat kode OF pada driver, kemungkinan besar ada kebocoran referensi
    • kebanyakan sistem tidak mengompilasi kernel dengan OF_DYNAMIC, sehingga reference count diabaikan dan masalah ini tidak ditemukan atau diperbaiki
    • tetapi abstraksi Rust untuk OF yang saya tulis menangani reference counting secara otomatis, jadi tidak perlu dipikirkan
  • Keuntungan menulis kode kernel dengan Rust dibanding C
    • saat menulis kode kernel dalam C, hanya ada dua pilihan
    • coba saja dan berharap reviewer menemukannya, atau menderita saat debugging
    • habiskan berjam-jam untuk memahaminya sebelum berani memakai kode tersebut, sambil berharap semua hal sudah tertangkap
    • ini juga menambah beban kerja reviewer dan maintainer
      • mereka harus meninjau submission untuk memastikan semua aturan tersembunyi yang tidak terdokumentasi dipatuhi
      • kadang masalah terlewat, dan kadang masalahnya begitu besar sampai kode harus direfaktor besar-besaran
  • Di Rust, semua ini hilang. Jika bisa dikompilasi, maka aman dan tidak akan ada malfungsi atau kebocoran referensi (kode unsafe adalah pengecualian, tetapi hanya itu yang perlu ditinjau, dan ada aturan bahwa bagian itu harus terdokumentasi dengan baik)
    • tentu tetap dibutuhkan code review dan bantuan dari pakar subsistem tertentu. Rust tidak secara ajaib membuat kode menjadi sempurna
    • tetapi Rust menghilangkan semua masalah dan kesalahan low-level yang konyol, sehingga kita bisa fokus pada masalah high-level
  • Pandangan terhadap para developer Linux
    • saya tidak menyalahkan para developer Linux atas dokumentasi yang tidak sempurna
    • kernel Linux sangat kompleks dan harus menangani banyak persoalan halus
    • sebagian besar API user space punya aturan yang jauh lebih sederhana untuk digunakan dengan aman
    • kernel itu sulit
    • bahkan developer kernel yang berpengalaman pun tetap sering salah dalam hal-hal seperti ini
    • ini bukan masalah keterampilan teknis, tetapi karena mustahil bagi manusia untuk menyimpan semua aturan kompleks ini di kepala dan mengeksekusinya dengan tepat setiap saat
  • Solusinya
    • kita butuh alat bantu
    • solusinya adalah Rust. Setelah semua aturan dienkodekan sekali ke dalam kode dan type system, kita tidak perlu mengkhawatirkannya lagi
    • sama seperti solusi untuk perdebatan gaya coding adalah mengenkodekan semua aturan ke dalam formatter otomatis
    • setelah itu kita bisa berhenti mencemaskan semua masalah low-level soal keamanan, ownership, dan sinkronisasi, lalu fokus pada hal yang lebih penting seperti desain driver dan subsistem tingkat tinggi
  • Pemformatan kode di proyek Rust for Linux
    • proyek Rust for Linux memang menerapkan rustfmt pada submission
    • saat menulis Rust untuk kernel, tidak perlu khawatir soal pemformatan kode atau keluhan saat code review
    • cukup jalankan make rustfmt

Opini GN⁺

  • Tulisan ini dengan baik menunjukkan masalah dokumentasi API dan keamanan dalam pengembangan kernel Linux. Ini juga memperlihatkan dengan jelas keterbatasan bahasa C dan kelebihan Rust
  • Namun, pernyataan bahwa "Rust adalah satu-satunya solusi" tampak agak berlebihan. Sebagian perbaikan juga mungkin dilakukan lewat cara lain seperti alat analisis statis
  • Rust memang menyelesaikan banyak masalah seperti keamanan memori, tetapi code review dan pengujian yang teliti tetap diperlukan. Rust bukan peluru perak
  • Beralih ke Rust juga dapat menghadirkan berbagai kesulitan, seperti kompatibilitas dengan kode C yang sudah ada dan kurva belajar developer. Adopsi bertahap tampaknya lebih diinginkan
  • Untuk memperbaiki praktik dan budaya lama di kernel Linux, selain Rust kemungkinan juga dibutuhkan upaya dari banyak sisi seperti dokumentasi, mentoring, dan komunikasi
  • Secara keseluruhan, tulisan ini menunjukkan potensi dan kelebihan Rust dalam pengembangan kernel Linux dengan baik, sambil tetap mewaspadai ekspektasi berlebihan atau pemujaan buta, sehingga menghadirkan sudut pandang yang seimbang. Meski adopsi Rust akan sulit secara teknis maupun kultural, dalam jangka panjang hal itu diharapkan dapat membantu meningkatkan keamanan dan kemudahan pemeliharaan kode kernel.

2 komentar

 
aer0700 2024-09-01

Rust... saya pribadi pernah mencoba mempelajarinya, tetapi di perusahaan kami masih belum mengadopsinya. Sudah ada segunung kode yang ditulis dengan C++, dan ada juga masalah bahwa SDM yang ada harus belajar Rust lagi... Saya dengar sudah ada perusahaan di Korea yang menerapkan Rust di production, jadi sepertinya akan bagus kalau ada yang membagikan pengalaman terkait atau semacamnya.

 
GN⁺ 2024-09-01
Komentar Hacker News
  • Bahasa seperti Rust dan Swift memiliki daya ekspresif tinggi sehingga compiler dapat memberi tahu keamanan thread dari tipe data atau metode

    • Saat code review, tidak perlu memeriksa satu per satu keamanan penggunaan pointer, dan dengan bahasa yang aman terhadap memori kita bisa fokus pada implementasi logika bisnis
  • Banyak library Rust yang dokumentasinya kurang memadai

    • Rust tidak menyelesaikan masalah dokumentasi API yang tidak lengkap; masalah ini diselesaikan oleh developer yang mendokumentasikan API dengan teliti
  • Mencoba menggunakan Rust seperti C lalu kesulitan karena borrow checker

    • Penting membaca function signature dan memeriksa &self atau &mut self
    • Jika ada &mut self, maka untuk berbagi instance antar-thread perlu menggunakan mutex
  • Dengan melihat API Rust, dalam banyak kasus kita bisa tahu cara menggunakannya dengan benar

    • Namun, beberapa API Rust tidak menunjukkan cara membuat tipenya hanya dari function signature sehingga perlu mencari di Google
  • Sebagai contoh konkret di Rust, ada cara menggunakan lock untuk melindungi data

    • Di Rust, lock membungkus data yang dilindungi sehingga data tidak bisa diakses tanpa melepas lock tersebut
  • Di bahasa lain juga, jika API diimplementasikan secara redundan, kejelasan kode dan dokumentasi bisa meningkat

    • Dari pengalaman terbaru, ada kasus perubahan yang salah di network stack lolos review dan masuk ke versi stabil
    • Untuk menghindari masalah seperti ini, sebaiknya menggunakan alat bantu
  • Saat memakai C dalam extension Python, ada masalah karena harus mengetahui calling convention

    • Dengan Rust dan PyO3, masalah ini hilang dan hambatan masuk menjadi lebih rendah
    • C++ juga menyediakan fitur serupa, tetapi tidak seaman Rust
  • Orang-orang seperti ini adalah pahlawan dan melakukan pekerjaan yang luar biasa

  • Kita selangkah lebih dekat untuk mewujudkan kode yang sepenuhnya mendokumentasikan dirinya sendiri