2 คะแนน โดย GN⁺ 2024-07-16 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ในงาน LSFMM+BPF Summit ปี 2024 มีการหารือแนวทางนำ Rust มาใช้กับระบบไฟล์ของ Linux และแพตช์ RFC ฉบับที่สองซึ่งออกมาต่อจาก RFC เดือนธันวาคม 2023 ก็เป็นศูนย์กลางของการถกเถียง
  • ฝั่ง Rust-for-Linux ต้องการใส่ข้อกำหนดของ API ระบบไฟล์ลงใน ระบบชนิดของ Rust เพื่อให้ตรวจจับข้อผิดพลาดได้ตั้งแต่คอมไพล์ จัดการการคืนทรัพยากรอัตโนมัติ และลดช่องโหว่ที่เกี่ยวข้องกับหน่วยความจำ
  • กรณีของ iget_locked() แสดงให้เห็นทิศทางที่ get_or_create_inode() ใน Rust จะใช้ ชนิดข้อมูลและการจัดการอัตโนมัติ เพื่อบังคับเรื่องการตรวจสอบ null การแยกสถานะ inode และการจัดการความล้มเหลว ซึ่งเดิมผู้เรียกใน C ต้องจัดการเอง
  • Dave Chinner, Christian Brauner, James Bottomley, Ted Ts'o และคนอื่น ๆ กังวลเรื่องชื่อที่ไม่สอดคล้องกันระหว่าง C API กับ Rust API การซิงก์ API ความต่างของวงจรชีวิตออบเจ็กต์ และภาระการดูแลรักษาเมื่อมี ระบบไฟล์มากกว่า 50 ตัว
  • แกนกลางของความขัดแย้งไม่ใช่ข้อดีของ abstraction ใน Rust เอง แต่เป็นเรื่องว่าเมื่อโค้ด C เปลี่ยนไปเรื่อย ๆ ใครจะเป็นผู้รับภาระของ ความเจ็บปวดในการตามให้ Rust binding และ abstraction สอดคล้องกัน

เซสชัน Rust สำหรับระบบไฟล์ใน LSFMM+BPF

  • ในงาน Linux Storage, Filesystem, Memory Management, and BPF Summit ปี 2024 Wedson Almeida Filho และ Kent Overstreet ได้พูดถึงแนวทางใช้ Rust กับระบบไฟล์ของ Linux
  • Almeida เคยส่งชุดแพตช์ RFC สำหรับ abstraction ของระบบไฟล์ใน Rust เมื่อเดือนธันวาคม 2023 และแนวทางนี้ก็มีความเห็นที่แตกต่างกันอยู่
  • ในวันเดียวกับที่มีเซสชันช่วงกลางเดือนพฤษภาคม Almeida ได้ส่งแพตช์ RFC เวอร์ชันที่สองขึ้นมาเพื่อให้หารือร่วมกับหัวข้อ Rust อื่น ๆ

เป้าหมายของ abstraction ระบบไฟล์ใน Rust-for-Linux

  • abstraction ระบบไฟล์ที่เสนอสะท้อนทิศทางที่โครงการ Rust-for-Linux project ต้องการผลักดัน
  • แกนหลักคือการแสดงข้อกำหนดของ API ระบบไฟล์ให้มากขึ้นผ่าน ระบบชนิดของ Rust เพื่อจับความผิดพลาดได้ตั้งแต่ขั้นคอมไพล์
  • ยังต้องการทำงานบางอย่างให้เป็นอัตโนมัติ ซึ่งในโค้ด C ทำได้ยาก
    • เช่น การคืนทรัพยากร
  • เป้าหมายคือทำให้ประสบการณ์พัฒนาระบบไฟล์มีประสิทธิภาพมากขึ้น ลดเวลาที่ใช้ดีบักปัญหาที่คอมไพเลอร์สามารถหาได้ และลด ช่องโหว่ที่เกี่ยวข้องกับหน่วยความจำ
  • Overstreet บอกว่าเขาเจอการไล่บั๊กที่กินเวลาสองสัปดาห์ใน bcachefs บ่อยเกินไป และมองว่า Rust ให้อะไรได้มากกว่า C
    • Rust กำจัดพฤติกรรมที่ไม่ถูกกำหนดไว้
    • ให้ความสามารถในการมองเห็นว่าเกิดอะไรขึ้นภายในโค้ด
    • หากสามารถพิสูจน์ความถูกต้องของโค้ด Rust ได้ บั๊กที่ขัดขวางการพัฒนาฟีเจอร์ก็น่าจะลดลงมาก

กรณีศึกษาระบบชนิดรอบ iget_locked()

  • Almeida ยกตัวอย่างในสไลด์ว่าฟังก์ชัน iget_locked() ในเคอร์เนลปัจจุบันมีข้อกำหนดที่ซับซ้อน
  • ผู้เรียกใน C ต้องจัดการหลายเงื่อนไขด้วยตัวเอง
    • ต้องตรวจว่าค่าที่คืนมาเป็น null หรือไม่
    • ต้องตรวจว่า struct inode ที่คืนมาเป็น inode ใหม่หรือ inode เดิม
    • ถ้าเป็น inode ใหม่ ต้องทำการ initialize ก่อนใช้งาน
    • หาก initialize ไม่สำเร็จ ต้องเรียก iget_failed()
  • Al Viro ไม่เห็นด้วยกับข้อกำหนดบางส่วนของผู้เรียก iget_locked() ที่อยู่ในสไลด์ของ Almeida และก็มีการโต้เถียงกันต่อในรายละเอียดของพฤติกรรม
  • Overstreet มองว่าหากครอบกฎเหล่านี้ไว้ใน ชนิดและ abstraction ของ Rust คอมไพเลอร์ก็จะสามารถบังคับให้จัดการอย่างถูกต้องได้
  • ฟังก์ชันฝั่ง Rust ที่ Almeida เสนอเป็นคู่กันคือ get_or_create_inode()
    • เช่นเดียวกับ C ยังต้องตรวจว่าล้มเหลวหรือไม่
    • หากสำเร็จ ผู้เรียกจะได้รับ inode แบบนับอ้างอิงปกติ หรือไม่ก็ inode ใหม่
    • สำหรับ inode ปกติ ตัวนับอ้างอิงจะถูกลดลงอัตโนมัติเมื่อไม่มีการอ้างอิงออบเจ็กต์อีกต่อไป
    • สำหรับ inode ใหม่ หากไม่ได้ initialize จะมีการเรียกการจัดการที่เทียบเท่า iget_failed() โดยอัตโนมัติ
    • เมื่อ inode ใหม่ถูก initialize แล้วหนึ่งครั้ง มันจะกลายเป็น inode ปกติ และหลังจากนั้นจะใช้การลดตัวนับอ้างอิงอัตโนมัติ
    • พฤติกรรมเหล่านี้ถูกบังคับผ่าน ระบบชนิด
  • Viro ตั้งคำถามว่าข้อจำกัดเหล่านี้จะถูกนิยามไว้ตรงไหนในซอร์สโค้ดจริง
  • Almeida ตอบว่าเขาต้องการทำความเข้าใจข้อจำกัดจาก Viro และนักพัฒนาระบบไฟล์คนอื่น ๆ ก่อน แล้วจึงสร้างชนิดและ abstraction ที่บังคับสิ่งเหล่านั้นได้

รอยขาดระหว่าง C API และ Rust API

  • Dave Chinner มองว่าหากชื่อของ C API และ Rust API ต่างกัน นักพัฒนาที่คุ้นกับโค้ด C จะดูแล้วไม่รู้ว่าคำเรียกฝั่ง Rust ที่สอดคล้องกันคืออะไร
  • ยังมีความกังวลด้วยว่าถ้าไม่ใช้ชื่อเดียวกัน API จะกลายเป็นสิ่งที่แปลกใหม่โดยสิ้นเชิงสำหรับชุมชนนักพัฒนาเดิม
  • เมื่อโค้ด C เปลี่ยน โค้ด Rust ก็ต้องเปลี่ยนตามด้วย จึงเกิดคำถามว่าใครจะเป็นคนรับงานนั้น
  • Almeida ยอมรับว่านี่เป็นประเด็นที่ต้องคุยกัน
    • เขาไม่ได้คัดค้านการเปลี่ยนชื่อ
    • แต่ก็ไม่คิดว่า iget_locked() เป็นชื่อที่ดีนัก และอาจมองว่าเป็นโอกาสในการตั้งชื่อที่ดีกว่า
  • Viro มองว่าการเลือก iget_locked() มาเป็นตัวอย่างไม่ค่อยเหมาะ เพราะมันไม่ใช่เมธอดสมาชิกของออบเจ็กต์ superblock แต่เป็นฟังก์ชันไลบรารี
  • Almeida ตอบว่า get_or_create_inode() ก็สามารถทำให้เป็นฟังก์ชันไลบรารีได้เช่นกัน และตัวอย่างนี้มีไว้เพื่อแสดงวิธีเข้ารหัสข้อจำกัดลงในชนิดข้อมูล

ทางเลือกระหว่าง abstraction แบบครอบจักรวาลกับแนวทางเน้นระบบไฟล์แบบเรียบง่าย

  • Christian Brauner มองว่าต้องตัดสินใจก่อนว่า abstraction ของ Rust จะเป็น abstraction ครอบจักรวาลสำหรับทุกระบบไฟล์ในเคอร์เนล หรือจะเน้นความสามารถที่จำเป็นสำหรับระบบไฟล์ที่เรียบง่ายกว่าและเขียนด้วย Rust
  • ในระยะยาว ถ้าฟังก์ชันอย่าง get_or_create_inode() มีข้อจำกัดมากกว่า iget_locked() มาก ก็อาจกลายเป็นปัญหาได้
  • โค้ด C โดยเฉพาะในช่วงแรกอาจพัฒนาเร็วกว่าโค้ด Rust ทำให้ต้องคอย ซิงก์ API ทั้งสองฝั่งตลอดเวลา
  • Overstreet มองว่าประเด็นสำคัญคือ เมื่อเพิ่ม abstraction ของ Rust แล้วจะทำ refactoring และจัดระเบียบไปพร้อมกันหรือไม่ และเขาเห็นอย่างชัดเจนว่านั่นเป็นสิ่งจำเป็น
  • James Bottomley มองว่าวงจรชีวิตของออบเจ็กต์ถูกเข้ารหัสอยู่ใน Rust API แต่ไม่มีสิ่งที่เทียบกันได้ใน C
    • ถ้าวงจรชีวิตออบเจ็กต์เปลี่ยนในฝั่งหนึ่ง ก็อาจทำให้เกิดบั๊กในอีกฝั่งได้
  • Chinner บอกว่าวงจรชีวิตของออบเจ็กต์ inode บางครั้งก็แตกต่างกันไปตามแต่ละระบบไฟล์
    • หากใส่ความเข้าใจเรื่องวงจรชีวิตแบบเดียวลงไปใน API ฟังก์ชันเหล่านั้นอาจใช้ไม่ได้กับบางระบบไฟล์
  • Almeida ตอบว่าตัวอย่างนี้จะใช้เฉพาะกับระบบไฟล์ที่เรียก iget_locked() อยู่แล้วและจะได้ประโยชน์จากมัน
    • นักพัฒนา Rust ไม่ได้พยายามบังคับให้ระบบไฟล์เปลี่ยนวิธีที่ใช้อยู่ในปัจจุบัน

“ใครจะเป็นคนรับภาระความเจ็บปวด”

  • Ted Ts'o บอกว่ามันดูเหมือนมีความพยายามจะชักชวนทุกคนให้หันมานับถือ “ศาสนา” Rust แต่ใน Linux มี ระบบไฟล์มากกว่า 50 ตัว และคงไม่เปลี่ยนกันได้ทันที
  • โค้ด C จะยังถูกปรับปรุงต่อไป และถ้าความเปลี่ยนแปลงนั้นทำให้ Rust binding พัง ระบบไฟล์ที่พึ่งพา binding นั้นก็อาจพังไปด้วย
  • Ts'o มองว่าในช่วงนี้ Rust binding ยังเป็นพลเมืองชั้นสอง และถ้า Rust binding พังก็เป็นปัญหาของนักพัฒนา Rust-for-Linux ไม่ใช่ปัญหาของทั้งชุมชนระบบไฟล์
  • เขามองว่าภายใน 1-2 ปี การพัฒนา Rust binding ควบคู่กับวิวัฒนาการของโค้ด C จะทำให้เห็นชัดเองว่าแนวทางใส่ความหมายจำนวนมากลงในระบบชนิดนั้นดีหรือไม่ดี
  • สำหรับ Ts'o การเปลี่ยนแปลงครั้งใหญ่สุดท้ายแล้วคือปัญหาเรื่อง การกระจายภาระความเจ็บปวด
    • นักพัฒนาที่เปลี่ยน C API อาจบอกได้ว่าตนยอมแก้โค้ด C ที่ได้รับผลกระทบ แต่จะไม่แก้ Rust binding เพราะไม่รู้ Rust
  • Almeida ตอบว่าเขาไม่ได้พยายามตรึง C API ไว้ แต่หากนักพัฒนาระบบไฟล์ช่วยอธิบายความหมายของ API เขาก็ต้องการนำสิ่งนั้นมาเข้ารหัสไว้ใน Rust
  • Bottomley มองว่ายิ่งเข้ารหัสความหมายไว้ใน binding มากเท่าไร ก็ยิ่งเปราะบางในแง่ของการซิงก์มากขึ้นเท่านั้น
  • Almeida ตอบว่าเมื่อ API เปลี่ยน ก็ต้องอัปเดตผู้ใช้ API เช่นเดียวกับผู้ใช้รายอื่นอยู่แล้ว

จะใส่อะไรไว้ในเมธอด ฟังก์ชัน และชนิดข้อมูล

  • Viro กลับมาตั้งข้อสังเกตอีกครั้งว่าทางเลือกแทน iget_locked() นั้นพึ่งพาเมธอด
    • เขามองว่าเมื่อใช้เมธอด อาร์กิวเมนต์จะไม่ได้ถูกระบุอย่างชัดเจน
  • Overstreet มองว่าความไม่ชอบเมธอดนั้นมาจากภาษาอย่าง C++ ที่พึ่งพา inheritance มากเกินไป
    • แต่ Rust ไม่ได้เป็นแบบนั้น และเมธอดใน Rust ส่วนใหญ่ก็เป็นเพียงองค์ประกอบทางไวยากรณ์
  • Jan Kara แยกความต่างระหว่างพฤติกรรมที่ติดมากับ inode เอง กับพฤติกรรมที่แฝงอยู่ในฟังก์ชัน iget_locked()
    • inode มีพฤติกรรมอย่างการนับอ้างอิงและการจัดการที่เกี่ยวข้อง
    • ส่วนฟังก์ชัน iget_locked() ก็มีพฤติกรรมเฉพาะของมันเอง
  • Overstreet และ Almeida ตอบว่าทั้งสองส่วนถูกเข้ารหัสไว้ในชนิดข้อมูล แต่แยกจากกัน และฟังก์ชันอื่นที่ใช้ชนิด inode ก็สามารถมีค่าที่ส่งคืนซึ่งมีคุณสมบัติต่างกันได้
  • Viro อธิบายว่าทำไม inode ใน VFS จึงทำงานในรูปแบบปัจจุบัน และเห็นด้วยว่าควรเริ่มจากจุดเล็ก ๆ แล้วค่อยดูทิศทางต่อไป
  • Overstreet บอกว่าตัวอย่างครั้งนี้อาจซับซ้อนเกินไปจนไม่เหมาะจะใช้เป็นจุดเริ่มต้น ส่วน Viro ตอบว่า “ไม่, ไม่ใช่แบบนั้น” ก่อนที่เซสชันจะจบลง

1 ความคิดเห็น

 
GN⁺ 2024-07-16
ความคิดเห็นบน Hacker News
  • ไม่เข้าใจตรงที่บอกว่าแต่ละไฟล์ซิสเต็มมี วงจรชีวิตของ inode แบบกำหนดเอง แต่กลับใช้ฟังก์ชันจัดการวงจรชีวิตเดียวกัน และต่างกันแค่เชิงความหมาย
    ถ้าฟังก์ชันเดียวกันต้องถูกใช้ต่างกันตามรายละเอียดการ implement ก็ฟังดูเหมือนตรงข้ามกับเลเยอร์ abstraction
    ถ้าวงจรชีวิตของ inode เป็นเรื่องเฉพาะของแต่ละไฟล์ซิสเต็ม ก็ควรจัดการด้วยฟังก์ชันเฉพาะของแต่ละไฟล์ซิสเต็ม

    • ผมก็สงสัยแบบเดียวกัน และดูเหมือนว่าพวกเขากำลังพยายามทำความเข้าใจหรือจัดทำเอกสาร C API ทั้งหมดเพื่อทำงานฝั่ง Rust
      เมื่อรวบรวมข้อมูลแบบนั้นไปเรื่อย ๆ ก็อาจเผยให้เห็นจุดที่ควร refactor เพื่อไม่ให้เกิดคำถามแบบนี้ตั้งแต่แรก ซึ่งเป็นเรื่องดี
    • ถ้าเป็นเอกสารที่เพิ่งเห็นเป็นครั้งแรก https://www.kernel.org/doc/html/latest/filesystems/vfs.html อาจช่วยได้
      เป็นภาพรวมของ เลเยอร์ VFS ที่จัดการพฤติกรรมเฉพาะของแต่ละไฟล์ซิสเต็ม ขณะเดียวกันก็รักษาอินเทอร์เฟซที่สอดคล้องกันไว้ฝั่งเคอร์เนล
    • ผมเข้าใจว่าแนวทางคือ abstract ส่วนที่ทำได้โดยทั่วไปให้มากที่สุดใน เลเยอร์ VFS แล้วให้เลเยอร์เฉพาะของไฟล์ซิสเต็มจัดการข้อยกเว้นที่ไม่เข้ากัน
      วงจรชีวิตของ inode อาจเป็นเพียงตัวอย่างตั้งต้นสำหรับเริ่มการอภิปรายก็ได้
    • ดูเหมือนต้องการให้คอมไพเลอร์ติดตาม อายุการใช้งานของ inode
      โดยให้คอมไพเลอร์ช่วยเรื่อง reference ชั่วคราว แต่ไฟล์ซิสเต็มยังคงต้องเก็บจำนวนลิงก์ไว้บนดิสก์
    • มีหลายฟังก์ชันที่ใช้สร้าง inode และใส่ลงในแคชได้ โดย iget_locked() ที่พูดถึงตรงนี้เป็นแพตเทิร์นเฉพาะแบบหนึ่งในนั้น
      ไม่ใช่ทุกไฟล์ซิสเต็มที่ใช้วิธีนั้น และบางสถานการณ์ก็ไม่ใช้
      เช่น FAT ไม่ใช้ เพราะมันสร้างหมายเลข inode ขึ้นมาเอง และรักษา mapping ของตัวเองจากตำแหน่งใน FAT ไปยัง inode
      นอกจากนี้ยังมีไฟล์ซิสเต็มอย่าง proc ที่ไม่แคชอ็อบเจ็กต์ inode
      ตัวอ็อบเจ็กต์ inode เองดูเหมือนจะมีการไหลของสถานะเหมือนกันไม่ว่ามาจากไหน ดังนั้นจากมุมมองของผู้ใช้ วิธีใช้ inode จึงไม่เปลี่ยน
      สิ่งที่ต่างกันคือเลเยอร์ไฟล์ซิสเต็มสร้างอ็อบเจ็กต์ inode และจัดการภายในอย่างไร
  • ผมสงสัยว่าเราอาจกำลังตั้งคำถามผิดอยู่หรือเปล่า
    Rust ควรเปลี่ยนให้เรียก C ได้ง่ายขึ้นกว่านี้หรือ?
    ผมเคยลอง Rust มาบ้างเล็กน้อย แต่ในมุมของนักพัฒนางานอดิเรก ก็ยังไม่ชัดเจนว่าควรทำงานร่วมกับ C อย่างไร
    ในทางกลับกัน ใน C++ หรือ Objective C แค่ include header ที่ถูกต้องแล้วเรียกฟังก์ชันก็ได้แล้ว
    Swift สามารถ include ไฟล์ Objective C ได้ และจากตรงนั้นก็เรียก C ได้
    ในกรณีนี้ แทนที่จะคาดหวังให้นักพัฒนาเคอร์เนลปรับตัวเข้ากับภาษา ผมคิดว่า ภาษา Rust เองควรยืดหยุ่นขึ้นอีกหน่อยหรือเปล่า

    • การเรียก C จาก Rust ค่อนข้างเรียบง่ายอยู่แล้ว
      แค่ประกาศฟังก์ชันภายนอกแล้วเรียกใช้งาน
      ตัวอย่างเช่น ตามที่อยู่ในหนังสือ Rust ที่ https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#usin... สามารถประกาศด้วย extern "C" ได้
      ถ้าไม่อยากเขียน declaration ทั้งหมดด้วยมือสำหรับไลบรารีที่ซับซ้อน ก็ใช้เครื่องมืออย่าง bindgen ที่สร้าง extern declaration จากไฟล์ header ของ C ให้อัตโนมัติได้: https://github.com/rust-lang/rust-bindgen
      จะโต้แย้งก็ได้ว่าถ้ามีของอย่าง bindgen รวมอยู่ใน Rust ให้ใช้ได้โดยไม่ต้องพึ่ง dependency ภายนอกหรือการตั้งค่า build.rs ก็คงดี แต่ประเด็นหลักของบทความนี้ไม่ใช่เรื่องนั้น
      ปัญหาไม่ใช่ binding ระดับล่าง แต่เป็น wrapper ระดับสูงที่เป็นสไตล์ Rust และไม่มีเครื่องมือทั่วไปใดที่สามารถสร้าง wrapper แบบนั้นจากโค้ด C ใด ๆ ได้โดยอัตโนมัติ
    • นี่ไม่ใช่จุดยากสำคัญของ Rust และไม่เกี่ยวกับหัวข้อของบทความด้วย
      บทความพูดถึงการหาวิธี implement ไดรเวอร์ filesystem ของเคอร์เนล ฯลฯ ด้วย Rust จริง ๆ
      อีกประเด็นสำคัญคือโค้ด Rust ภายในเคอร์เนลย่อมต้อง consume interface ของ C อย่างหลีกเลี่ยงไม่ได้
      สำหรับ use case ที่นึกถึง bindgen ค่อนข้างเหมาะมาก: https://github.com/rust-lang/rust-bindgen
    • ในทางปฏิบัติทำได้ค่อนข้างง่าย
      ถ้าจะเรียกจาก Rust ก็ประกาศ extern "C" fn foo() -> T แล้วส่ง link flags ผ่าน attribute #[link] หรือผ่าน build.rs ก็ได้
      สามารถสร้าง binding ล่วงหน้าด้วย crate bindgen หรือสร้างใน build.rs แล้ว include ด้วย include!() ได้
      โดยปกติจะสร้าง crate -sys ที่มีเฉพาะ binding ที่ generate มา แล้วโค้ดจริงก็ use binding จาก sys crate นั้นเหมือนปกติ
      ใน C++ และ Objective C ก็ไม่ใช่แค่ include header ที่ถูกต้องเท่านั้น แต่ยังต้อง link กับไลบรารีด้วย
    • ใจความสำคัญคือ Rust สามารถ model invariant ที่ C แสดงออกมาไม่ได้
      การเรียกไปกลับสองทางทำได้ แต่ถ้า C ไม่สามารถแสดงสิ่งที่ Rust แสดงได้ ก็จะมีผลสำคัญต่อการออกแบบ API ที่ทั้งสองฝั่งต้องใช้ร่วมกัน
    • การเรียก C นั้นเรียบง่ายมากอยู่แล้ว ดังนั้น Rust ไม่จำเป็นต้องเปลี่ยนให้ทำได้ง่ายขึ้นอีก
      แค่ประกาศฟังก์ชัน C เป็น extern "C" แล้วเรียกใช้
      โดยปกติต้องใช้ unsafe และต้องแปลง reference เป็น raw pointer หรือ cast แต่ตัว syntax เองเรียบง่าย
      มีเครื่องมือที่ scan ไฟล์ header ของ C แล้วสร้าง declaration ให้ด้วย และ bindgen เป็นตัวที่ใช้กันมากที่สุด
      ประเด็นของบทความนี้ใกล้เคียงกับเรื่องว่าจะใช้ Rust อย่างไรมากกว่าตัวภาษาเอง
      นักพัฒนา Rust-for-Linux อยากใช้ความสามารถและ type system ของ Rust เพื่อ encode semantics ของการเรียก API ให้ปลอดภัยขึ้นและเกิดข้อผิดพลาดน้อยลง
      ฝั่งคนที่ใช้ C กังวลว่าถ้าทำแบบนั้นแล้วอาจทำให้การพัฒนาพฤติกรรมและ semantics ของ C API ทำได้ยากขึ้น
      เพราะเมื่อ C API เปลี่ยน Rust API ก็ต้องแก้ตาม และพวกเขาไม่อยากแบกรับงานนั้น
      ทางเลือกที่น่าจะยอมรับได้ง่ายกว่าคือใช้ความสามารถและ type system ของ Rust ให้น้อยลงในการ encode semantics ลงใน Rust API
      แบบนั้นเมื่อ C API เปลี่ยน การอัปเดต Rust API ก็จะเป็นงานเชิงกลและง่ายขึ้น แต่ถ้า Rust-for-Linux ไม่สามารถใช้ความสามารถของ Rust เพื่อสร้าง API ที่ดีและปลอดภัยกว่าได้ ก็เกิดคำถามว่างานนี้มีความหมายอะไร
      อย่างไรก็ตาม มันก็แปลกนิดหน่อยที่จะพูดเรื่องนี้แบบฟันธง ทั้งที่ยอมรับว่าไม่ได้เข้าใจภาษาอย่างเพียงพอ
  • ผมไม่ค่อยรู้ filesystem ของ Linux จึงไม่ชัดเจนว่า Rust API นี้เป็นการห่อ C API หรือเป็นการ implement ใหม่
    ถ้าเป็นการ implement ใหม่หรือเป็น API แยกต่างหาก การคงชื่อให้เหมือน C API ไว้ดูเหมือนจะยิ่งสร้างความสับสนมากขึ้นเมื่อเวลาผ่านไป
    แม้ในช่วงแรกมันอาจช่วยให้นักพัฒนาที่คุ้นเคยเข้าใจได้เร็วขึ้นก็ตาม

    • Almeida แสดงสิ่งที่เทียบเท่ากับ iget_locked() ใน Rust และชื่อคือ get_or_create_inode()
      คำตอบดูเหมือนว่าจะเป็นการ implement ใหม่ และไม่ได้ใช้ชื่อเดียวกัน
  • เมื่อคิดถึงรูปแบบที่การถกเถียงแบบนี้มักจะไหลไปและขนาดของการเปลี่ยนแปลงแล้ว การอภิปรายครั้งนี้ถือว่า สุภาพอย่างน่าประหลาดใจ
    ผมไม่เห็นด้วยกับบรรยากาศเชิงลบใน thread นี้
    ผมค่อนข้างมองโลกในแง่ดี เพราะผู้เกี่ยวข้องสื่อสารจุดเจ็บปวดหลักได้ชัดเจนโดยไม่พูดเหลวไหล

    • ที่อ่านต่อก็เพราะ การเรียบเรียงบันทึกที่ยอดเยี่ยม มากกว่าเนื้อหาเสียอีก
      การอภิปรายจริงคงดุเดือด กระจัดกระจาย และมีการจับผิดกันเยอะ สมกับเป็นการถกเถียงเรื่องภาษาโปรแกรมมิ่งระหว่างพวก geek ที่มีความเห็นแรง ๆ
      ดูเหมือน Jake Edge ผู้เขียนสรุปนี้จะเก่งมากในการตัดส่วนเหล่านั้นออกและเขียนเฉพาะแก่นสำคัญ
  • คอมเมนต์บางส่วนใต้หน้า lwn.net ค่อนข้างหยาบคาย
    ลองจินตนาการว่าคุณได้รับคอมเมนต์อย่าง Science advances one funeral at a time ในโปรเจกต์โอเพนซอร์สที่คุณกำลังมีส่วนร่วมอยู่ก็พอ

  • การที่เคอร์เนล Linux มีตัวเลือกมากขึ้นนั้นเป็นประโยชน์เสมอ
    แต่ Rust อาจไม่ใช่คำตอบของทุกสิ่ง
    Rust พยายามอย่างเต็มที่เพื่อรับประกันโมเดลการเขียนโปรแกรมที่ปลอดภัย แต่โมเดลนั้นก็มีข้อจำกัด
    อาจดูเหมือนว่าถ้าเป็นปัญหาหน่วยความจำก็ใช้ Rust และถ้าเป็นปัญหาคอนเคอร์เรนซีก็เปลี่ยนมาใช้ Rust แต่หากไม่มีบล็อก unsafe ก็ไม่สามารถทำทุกอย่างที่ C ทำได้
    Rust อาจให้มุมมองใหม่ต่อปัญหาเหล่านี้ได้ แต่ไม่ใช่วิธีแก้ที่สมบูรณ์แบบ

    • ข้อได้เปรียบใหญ่ของ Rust ในงานนี้คือการที่มันมีท่าทีเชิงรุกในการ ห่อหุ้มปัญหาด้านความปลอดภัยเหล่านั้นไว้ในชนิดข้อมูล และบทความนี้ก็พูดถึงเรื่องนั้นพอดี
      C โดยเฉพาะ C ที่ใช้ในเคอร์เนล โยนความรับผิดชอบให้แต่ละคนต้องรู้กฎโดยนัยทั้งหมดอย่างครบถ้วน
      สิ่งนั้นขยายต่อไปไม่ได้
      แม้แต่นักพัฒนาเคอร์เนลที่ใช้โครงสร้างข้อมูลเดียวกันมารวมอยู่ในห้องเดียวกัน ก็ยังตกลงกันเรื่องกฎนั้นได้ไม่ครบถ้วน
      Rust เก่งในการทำให้กฎที่ต้องรู้ปรากฏชัด และถ้าคนอื่นสามารถรับประกันการปฏิบัติตามกฎได้ ก็ทำให้เรื่องนั้นไม่ใช่ปัญหาของเรา
      บางครั้งผลลัพธ์อาจไม่เหมาะที่สุด แต่ในเคอร์เนล Linux ค่าเริ่มต้นที่ไม่เหมาะที่สุดก็ถูกต้องอยู่บ่อยครั้ง และสำหรับคนที่มีแรงพอจะเรียนรู้กฎประหลาดเพิ่มอีกหกข้อเพื่อให้ได้ประสิทธิภาพที่ดีกว่า ก็แค่ให้ทางออกด้วย unsafe
    • สามารถใช้บล็อก unsafe ได้
      เพียงแต่ควรใช้เฉพาะเมื่อจำเป็นเท่านั้น
      การใช้บล็อก unsafe ที่มีขอบเขตผลกระทบจำกัดมาก ไม่ได้หมายความว่าหลักประกันทั้งหมดที่ได้จากโค้ดส่วนที่เหลือจะหายไป
    • เป็นความจริงที่งานระดับต่ำจำเป็นต้องใช้โค้ด unsafe
      แต่การที่ต้องใช้ unsafe จึงสรุปว่า Rust ไม่เหมาะนั้นเป็นความเข้าใจผิด
      การแบ่งแยกระหว่าง safe/unsafe ของ Rust มีจุดประสงค์เพื่อทำเครื่องหมายให้ชัดเจนว่าส่วนใดของโค้ดไม่ปลอดภัย เพื่อให้สามารถมุ่งตรวจสอบเฉพาะส่วนเล็ก ๆ นั้น และเชื่อได้ว่าถ้าส่วนนั้นถูกต้อง ส่วนที่เหลือก็จะทำงานได้
    • สงสัยว่าในบรรดาสิ่งเหล่านี้ มีมากแค่ไหนที่จำเป็นจริง ๆ แบบชัดเจน 100%
      ในโค้ดไฟล์ซิสเต็ม มีเหตุผลที่ดีอะไรที่จำเป็นต้องเป็น unsafe หรือไม่?
      น่าจะเป็นเซตย่อยเล็กมาก ๆ ที่จำเป็นแค่ไม่กี่จุด
    • ชอบ Rust เพราะมีบางครั้งที่ความเข้าใจต่าง ๆ เข้ากันได้พอดี แต่รู้สึกว่าด้าน async ยังมีส่วนที่หยาบอยู่มาก
      ไม่ค่อยเป็นธรรมชาติที่จะเข้าใจว่าเกิดอะไรขึ้นข้างใน
  • ดูจากบันทึกการประชุมแล้ว Rust ในเคอร์เนลดูเหมือนเป็น ต้นทุนความซับซ้อนเพิ่มเติม
    ถ้าเขียนระบบปฏิบัติการใหม่ตั้งแต่ต้น ก็จะใช้พลังของภาษาได้เต็มที่
    แต่เมื่อเอามาเติมข้าง ๆ โค้ดเบสขนาดใหญ่ที่มีอยู่แล้ว ก็เกิดปัญหาเพิ่มเติมอย่างที่เห็นที่นี่

    • ถูกต้อง แต่ต้นทุนนั้นควรถูกชดเชยด้วย การพัฒนาไดรเวอร์ ที่ง่ายขึ้น
      ดูบล็อกที่บอกว่าไดรเวอร์ GPU ของ Asahi Linux ที่เขียนด้วย Rust ถูกสร้างขึ้นในหนึ่งเดือนได้
      ค้นหา tales of the m1 gpu ใน Google ก็ได้ และผู้เขียนมีความคิดในแง่ลบอย่างมากต่อ Hacker News
      ถ้าต้องการก็อ่านได้จากลิงก์นี้: https://asahilinux.org/2022/11/tales-of-the-m1-gpu/
      จะใช้ได้ทั่วไปแค่ไหนต้องดูกันในอีกไม่กี่ปีข้างหน้า
    • รู้สึกอย่างแรงว่ากำลังพลาดสิ่งที่ดีไปเพราะไล่ตามความสมบูรณ์แบบ
    • เห็นด้วยกับข้อดีของ Rust แต่โดยส่วนตัวมองว่าเหตุผลเอาชนะกระแสโฆษณาเกินจริงได้ยาก
      ต้นทุนนั้นจะถูกมองว่าเป็นสิ่งจำเป็นเพื่อยอมรับอนาคตและความก้าวหน้า
      สงสัยว่าทำไมจึงไม่จำกัดไว้แค่ เซตย่อยที่ปลอดภัย แทนที่จะกระโดดเข้าไปในกระแสขนาดใหญ่ที่มีบั๊กและการประนีประนอมมากมายที่ยังไม่รู้แน่
    • ถ้าเป็นโค้ดเพิ่มเติม ก็พูดได้ว่าไม่ใช่แค่ Rust แต่อะไรก็ตามล้วนเพิ่มความซับซ้อน
      ไม่ได้หมายความว่าเพราะมันใหญ่เกินไปแล้ว จึงต้องหยุดนวัตกรรมและเข้าสู่สถานะบำรุงรักษาไปอย่างไม่มีกำหนด
      เหมือนภาษีในโลกจริง ถ้าต้นทุนของด้านหนึ่งถูกใช้เพื่อชดเชยปัญหาอีกด้าน ก็อาจไม่ใช่การสูญเสียสุทธิ
      การดูแค่การถกเถียงเดี่ยว ๆ ที่ยังไม่ได้ข้อสรุป แล้วบอกว่ามันจะชดเชยปัญหาใด ๆ ไม่ได้เลย ดูเป็นเหตุผลที่สั้นไปหน่อย
  • ส่วนที่บอกว่าชื่อของ C API กับ Rust API ไม่ตรงกันจนดูโค้ด C แล้วไม่รู้ว่าจะเรียก Rust ที่เทียบเท่ากันอย่างไรนั้น ดูเหมือนเป็นการต่อสู้กับ ธรรมเนียมการตั้งชื่อ แบบเก่า
    เคยมีกรณีที่แก้ได้ดีด้วยการคงชื่อเดิมไว้ และเมื่ออยากได้ชื่อทางเลือก ก็ให้ชื่อใหม่ห่อหุ้มชื่อเก่าแทน
    ถึงอย่างนั้น การตั้งชื่อก็ยังยากอยู่ดี

    • เป็นหนึ่งในสองปัญหาใหญ่ของวิทยาการคอมพิวเตอร์
      อีกสองอย่างที่เหลือคือคอนเคอร์เรนซีและข้อผิดพลาด off-by-one