เริ่มต้นคู่มือการเขียนระบบไฟล์ FUSE ด้วย Python
(gwolf.org)- โปรเจ็กต์ระบบไฟล์สำหรับการสอนกับการเตรียมบรรยายที่ ChiPy มาบรรจบกัน จนเริ่มมีคู่มือบน GitLab สำหรับสร้าง ระบบไฟล์แบบ FUSE ด้วย Python ทีละขั้นตอน
- FIUnamFS ที่ใช้ในชั้นเรียนเป็นระบบไฟล์ตัวอย่างแบบง่าย มีการจัดสรรไฟล์แบบต่อเนื่อง ไม่รองรับไดเรกทอรีย่อย และจำกัดขนาดไว้ที่ฟลอปปีดิสก์ 1.44MB
- ตลอดหกภาคการศึกษา มีการมอบหมายงานให้นักศึกษาภาคการศึกษาละ 30~40 คน แต่มีผู้ส่งงาน การทำ FUSE จริงเพียงคนเดียว จึงยิ่งเห็นความจำเป็นของสื่อ Python FUSE ที่ทำตามได้ง่าย
- คู่มือใหม่นี้อยู่ในรูปแบบ แบบฝึกหัดแบบค่อยเป็นค่อยไป โดยเริ่มจากระบบไฟล์ว่างเปล่าแล้วค่อยเพิ่ม system call และฟังก์ชันต่าง ๆ รวมถึงการทำงานอ่าน/เขียนบน RAM และการทำ passthrough แบบอ่านอย่างเดียว
- ยังมีตัวอย่างสั้น ๆ อย่าง DNS, การคอมไพล์ Markdown แบบทันที, unzip และระบบไฟล์ลบคอมเมนต์ เพื่อให้นักศึกษาได้เรียนรู้ FUSE ผ่าน ตัวอย่างที่ใช้งานได้จริง
คู่มือ Python FUSE ที่เริ่มต้นจากโปรเจ็กต์ในชั้นเรียน
- หลังได้รับข้อเสนอให้บรรยายกับ Chicago Python User Group ที่ DebConf22 และมีการพูดถึงเรื่องนี้อีกครั้งที่ DebConf24 จึงเริ่มมองหาหัวข้อบรรยายเกี่ยวกับ Python
- แม้จะไม่ได้มองว่า Python เป็นภาษาหลักของตัวเอง แต่มันเป็นภาษาที่นักศึกษาตามได้ดีที่สุด จึงใช้ Python ในการสอน
- โปรเจ็กต์ประจำวิชา FIUnamFS เป็นตัวย่อของ “Facultad de Ingeniería, Universidad Nacional Autónoma de México” และเป็นระบบไฟล์ที่ใช้ในชั้นเรียนของคณะวิศวกรรมศาสตร์ มหาวิทยาลัยอิสระแห่งชาติเม็กซิโก
- ทำงานบนพื้นฐานของ การจัดสรรไฟล์แบบต่อเนื่อง
- ไม่รองรับไดเรกทอรีย่อย
- โดยทั่วไปจำกัดขนาดเท่าฟลอปปีดิสก์ 1.44MB
- ใช้เป็นระบบไฟล์ตัวอย่างแบบง่ายที่เขียนสเปกและอิมพลีเมนต์ได้ไม่ยาก
- ผู้สอนได้ขอให้นักศึกษาสร้างอินเทอร์เฟซที่ประณีตกว่าเมนูธรรมดา และมองว่า FUSE เหมาะสำหรับทำให้ผู้ใช้ใช้งาน FIUnamFS ได้โดยไม่ต้องรับรู้เบื้องหลัง
- โปรเจ็กต์นี้ถูกมอบหมายมาแล้วหกภาคการศึกษา ภาคการศึกษาละ 30~40 คน แต่มีนักศึกษาเพียงคนเดียวที่ส่งงานอิมพลีเมนต์ FUSE จริง
ข้อจำกัดของสื่อเดิมและตัวเลือกต่าง ๆ
- แม้จะมีตัวอย่างและบทความเกี่ยวกับ Python FUSE อยู่แล้ว แต่หลายชิ้นยังไม่พอสำหรับการทำตามด้วยตัวเอง หรือเป็นข้อมูลที่เก่าแล้ว
- อินเทอร์เฟซ FUSE ที่ใช้ได้จาก Python ก็ยังไม่ได้ถูกรวมเป็นมาตรฐานเดียว ทำให้เลือกยากว่าจะเริ่มจากที่ไหน
โครงสร้างของคู่มือบน GitLab
- โปรเจ็กต์ GitLab ใหม่ a hand-holding guide to writing FUSE-based filesystems in Python แสดงการอิมพลีเมนต์ระบบไฟล์ FUSE ที่ทำงานได้จริงหลายแบบแบบทีละขั้น
- บางส่วนทำงานบนพื้นฐานของ RAM
- บางส่วนอิมพลีเมนต์แบบ passthrough
- มีแผนจะเพิ่มระบบไฟล์ที่อิงกับอุปกรณ์บล็อกเสมือนสำหรับการอิมพลีเมนต์แบบ FIUnamFS
- ปัจจุบันมีไฟล์แบบค่อยเป็นค่อยไปอยู่ห้าไฟล์ เริ่มจากระบบไฟล์ว่างเปล่าที่ง่ายที่สุด แล้วเพิ่ม system call และความสามารถต่าง ๆ ทีละอย่าง
- ยังมีตัวอย่างสั้นและมีประโยชน์ที่น่าจะทำให้นักศึกษาสนใจรวมอยู่ด้วย
- ตัวอย่างเหล่านี้มีขนาดเพียงไม่กี่สิบบรรทัด จึงเหมาะกับการใช้สอนในชั้นเรียน และ
uncommentfsจะลบคอมเมนต์กับช่องว่างออกโดยอัตโนมัติ
กำหนดการบรรยายและสื่อที่เผยแพร่
- การบรรยายที่ ChiPy จัดขึ้นแบบออนไลน์ในวันที่ 10 ตุลาคม 2024 เวลา 18:30 GMT-6
- หัวข้อเดียวกันนี้มีกำหนดจะบรรยายที่ Jornadas Regionales de Software Libre และ nerdear.la ด้วย
- หลังการบรรยายมีการเผยแพร่วิดีโอด้วย
- วิดีโอบรรยาย ChiPy: A hand-holding guide to writing FUSE-based filesystems in Python
- วิดีโอบรรยายภาษาสเปน: Aprendiendo y enseñando a escribir sistemas de archivo en espacio de usuario con FUSE y Python
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ใน [0] บน GitHub ของ libfuse มีตัวอย่างสำหรับ C/C++ จัดเรียงตามระดับความซับซ้อนไว้อย่างดี
passthrough.c มิเรอร์ไฟล์ซิสเต็มที่มีอยู่ แต่ระบุไว้ว่า “ประสิทธิภาพแย่มาก” ส่วน passthrough_fh.c ระบุว่า “ไม่ได้แย่ขนาดนั้น”
passthrough_ll.c เขียนด้วย API ระดับต่ำ และบอกว่า “แย่น้อยที่สุดในสามตัว” ส่วน passthrough_hp.cc เป็นเวอร์ชันประสิทธิภาพสูงที่เขียนด้วย C++
โปรเจกต์ FUSE ที่น่าสนใจที่จดไว้มี การแบ่งไฟล์ขนาดใหญ่ [1], แสดงสแนปช็อตแบบ incremental ของ ZFS เป็นไฟล์ [2], การบีบอัดไฟล์ซิสเต็มแบบโปร่งใส [3], และตัวเลือกสำหรับเมานต์ archive เป็นไฟล์ซิสเต็ม [4], [5]
[0] https://github.com/libfuse/libfuse/tree/master/example
[1] https://github.com/seiferma/splitviewfuse
[2] https://github.com/UNFmontreal/zfs_fuse_snapshot
[3] https://github.com/FS-make-simple/fusecompress
[4] https://github.com/google/fuse-archive
[5] https://github.com/mxmlnkn/ratarmount
ที่จุดเมานต์ของทุก dataset จะมีโฟลเดอร์
.zfsที่ซ่อนอยู่ซึ่งแม้แต่ls -Aก็ไม่แสดง และถ้าเชื่อว่ามีอยู่ก็cdเข้าไปตรง ๆ ได้เลยข้างใต้นั้นมีโฟลเดอร์
snapshotและภายในมีโฟลเดอร์ของแต่ละสแนปช็อตของ dataset นั้น พร้อมไฟล์ของสแนปช็อตอยู่ข้างในตัวอย่างเช่น
/etc/hostsของสแนปช็อต zrepl_20241011_010143_000 จะอยู่ที่/.zfs/snapshot/zrepl_20241011_010143_000/etc/hostsหากไม่ชอบพฤติกรรมซ่อนแบบมายากลนี้ ก็สามารถตั้งค่าให้มองเห็นเหมือนโฟลเดอร์ทั่วไปได้ด้วย
zfs set snapdir=visibleดีใจที่ได้เห็นลิงก์ที่เกี่ยวข้อง และถ้ามี tutorial หรือ guide เกี่ยวกับ FUSE ที่ช่วยได้ เพราะความคุ้นมือเริ่มฝืดไปบ้าง ก็อยากได้เช่นกัน
ชอบ FUSE แต่ก็ไม่ใช่ตัวเลือกเดียว และเมื่อไม่นานมานี้ลองทำไฟล์ซิสเต็มเสมือนด้วย โปรโตคอล 9p แล้วค่อนข้างสนุก
เท่าที่จำได้ใช้ py9p และประสบการณ์กับ Python ดีกว่า fuse-python มาก
ถ้าต้องการก็สามารถใช้ 9pfuse เพื่อเมานต์บริการ 9p ผ่าน FUSE ได้ แต่ฉันใช้ไคลเอนต์ v9fs ของเคอร์เนล
ถ้าเป้าหมายคือแค่ส่งต่อไฟล์ซิสเต็มข้ามเครือข่าย คิดว่าเคยใช้เซิร์ฟเวอร์ 9p อย่าง diod และโดยรวมเป็น ecosystem เล็ก ๆ ที่น่าลองสำรวจ
โน้ตของฉันอยู่ที่ [1] แต่ส่วนใหญ่เป็นชุดลิงก์ไปยังเอกสารต้นทาง
FUSE ก็ดี แต่ 9P ใช้งานได้ทั่วไปมากกว่า และมี implementation คุณภาพดีในหลายที่ รวมถึง Windows
อย่างไรก็ตามยังไม่มั่นใจเรื่องลักษณะด้านประสิทธิภาพของ 9p เคยเห็นคนบอกว่าช้า แต่ยังไม่เห็นข้อมูลที่ฟันธงได้
อยากรู้ว่ามี benchmark หรือข้อมูลอะไรไหม
[0]: https://github.com/chaos/diod/blob/master/protocol.md
[1]: https://athenaeum.wiki/Zettelkasten/9p
ต้องการอ่านแบบสุ่มเหมือนไฟล์ในเครื่อง โดยไม่ต้องดาวน์โหลดไฟล์ใหญ่ทั้งหมดก่อน
หนึ่งในความเจ็บปวดที่เจอคือ block size ของ FUSE เล็กเกินไป ทำให้การเรียก HTTP ไปยัง backend มี latency และ churn สูง และต้องมีลอจิก caching/read-ahead ที่ค่อนข้างซับซ้อน
ลอจิก read-ahead ของเคอร์เนลดูเหมือนไม่ทำงานเลย และตอนนั้นไม่ได้ขุดลึก นอกจากยังหาวิธีกระตุ้นมันไม่เจอ
ดู FAQ ได้ที่ https://virtio-fs.gitlab.io
ถึงอย่างนั้นก็ยังเป็นโปรเจกต์ที่เจ๋ง
ถ้ารู้เรื่องนี้ตอนที่ต้องทำขั้นตอนเดียวกันเป๊ะเมื่อเดือนก่อนก็คงดี
ด้วยความพยายามอย่างสิ้นหวังที่จะทำให้การใช้งาน Jira น่าหงุดหงิดน้อยลง ผมนึกถึงโปรเจกต์ jira-as-filesystem ที่สร้างทรีโดยใช้การจัดหมวดหมู่ issue ภายใน
ผมให้ไดเรกทอรีแทน issue, ไฟล์แทนฟิลด์ของ issue และไดเรกทอรีย่อยแทน issue ที่เชื่อมโยงกัน แล้วสุดท้ายก็เลือกใช้ fuse-python
พักงานไปช่วงหนึ่ง แต่เริ่มเจอปัญหาตั้งแต่ระดับ abstraction แล้ว
ถ้าใช้ชื่อไดเรกทอรีเป็นแค่ ID ของ issue ระบบอัตโนมัติจะทำได้ง่าย แต่พอ
lsแล้วเห็นแต่ ID ที่อ่านไม่รู้เรื่องเต็มไปหมด ทำให้คนค้นดูได้ยาก เลยเพิ่มชนิดไดเรกทอรีคู่ขนานแบบ-with-summaryที่ต่อท้าย ID ของ issue ด้วยสรุปแบบ slugคือมี jira-as-filesystem หนึ่งชุดสำหรับไฟล์ต้นฉบับ แล้วมีทรี symbolic link สำหรับให้มนุษย์สำรวจและโต้ตอบ โดยวางลิงก์หลายอันไปยังไฟล์เดียวกันในหลายตำแหน่งที่เกี่ยวข้อง
อาจเป็นการเพิ่มชั้นมากเกินจำเป็นเพราะผมยังเข้าใจไม่พอ แต่ในเชิงเทคนิคดูเหมือนจะแก้ปัญหา abstraction ที่พูดถึงตอนนี้ได้
ใน Linux สมัยใหม่ ดิสก์ถูกอ้างถึงได้ทั้งในฐานะ block device และ UUID ดังนั้นผมคิดว่าแนวทางนี้ใช้ได้และสอดคล้องกับสิ่งที่คาดหวัง
แต่ส่วนตัวคงไม่ใช้ เพราะ JIRA เองก็ซับซ้อนพออยู่แล้ว
ตัวอย่าง: https://github.com/coddingtonbear/jirafs
1234-human-senseเฉย ๆ ไม่ได้เหรอ?มันมีข้อมูลทั้งสองแบบ และดูเหมือน parse ง่ายด้วย
มีตัวเลือกการเมานต์ FUSE เยอะมากจริง ๆ โดยแต่ละตัวมีจุดประนีประนอม ประสิทธิภาพ และฟีเจอร์แตกต่างกัน
มีทั้ง s3fs, goofys, seaweed, minio, Google Drive ฯลฯ และ JuiceFS ก็น่าสนใจมากสำหรับการเมานต์ object storage แล้วเข้าถึงในแบบ POSIX พร้อม metadata ที่คาดหวังจากระบบไฟล์แบบดั้งเดิม
https://juicefs.com
ดีเลย
คำถามใกล้เคียงคือ ช่วงหลังผมเห็นบางกรณีที่นำ ระบบไฟล์บนพื้นฐาน NFS มาใช้ เพราะเป็นโปรโตคอลที่รองรับกว้างกว่า
ดูเหมือน rclone จะทำแบบนี้บน Mac มีไกด์หรือบทความเปรียบเทียบแนวทางนี้ไหม?
มันทำงานได้แทบเหมือนตัวทดแทน ไม่ต้องใช้ kernel extension และเปิด NFS server ในเบื้องหลังแล้วเมานต์ด้วยฟังก์ชันของ macOS
ประสิทธิภาพก็ค่อนข้างดี
ถ้าอยากเห็นว่าผลิตภัณฑ์ที่ทำเสร็จแล้วหน้าตาเป็นอย่างไร ลองดูตัวจัดการเพลง azuline/rosé ที่มี virtual filesystem
เป็น codebase ที่ยอดเยี่ยม มีคอมเมนต์ คำอธิบาย type และเทสต์จำนวนมาก น่าจะเรียนรู้ได้ง่าย
https://github.com/azuline/rose
ถ้าสนใจ FUSE โปรเจกต์คู่กันอย่าง CUSE ก็น่าสนใจเช่นกัน
CUSE คือการจำลองไดรเวอร์ character device ใน userspace ทำให้เลียนแบบฮาร์ดแวร์ได้โดยไม่ต้องคอมไพล์ kernel module ใหม่
ช่วงหลังผมใช้มันเขียนอุปกรณ์ฮาร์ดแวร์ที่รองรับ IOCTL ด้วย Python
ผมหาไลบรารี Python ดี ๆ ที่ใช้งานง่ายไม่เจอ และเอกสารก็มีน้อย แต่สุดท้ายก็เขียนได้ด้วยไลบรารี ctypes FFI เพียงอย่างเดียว
ส่วนเดียวที่ไม่ค่อยเป็นธรรมชาติทันทีสำหรับคนที่ไม่เคยเขียน kernel driver คือ IOCTL จะมีการเรียกมาเป็นคู่ เพราะต้องปรับขนาดบัฟเฟอร์ใหม่สำหรับการอ่าน/เขียนแต่ละครั้ง
โชคดีที่ CUSE มีโหมด debug ที่แสดงไบต์อินพุตและเอาต์พุตทั้งหมด
เดิมที CUSE ถูกทำขึ้นเพื่อสร้างอุปกรณ์เสียงใน userspace¹ แต่ก็ถูกใช้กับกรณีอย่าง TTY แบบกำหนดเองด้วย และผมใช้มันสร้างอุปกรณ์ SPI เสมือน
หวังว่าจะเป็นประโยชน์กับใครสักคน และอยากให้โปรเจกต์นี้ได้รับความสนใจมากขึ้น
¹ https://lwn.net/Articles/308445/
นานมาแล้วผมเคยสร้าง ระบบไฟล์ FUSE ด้วย Python[1] เพื่อโต้ตอบกับระบบวิกิชื่อ dokuwiki
สร้างอยู่บน hde llfuse[2] ซึ่งต้อง implement API ระดับต่ำจำนวนมากที่ไม่ได้เกี่ยวข้องโดยตรงกับ dokuwiki
ดังนั้นผมจึงสร้าง easyfuse[3][4] เป็น wrapper สำหรับห่อส่วนที่ไม่เกี่ยวกับการ implement dokuwiki และถ้าคิดจะสร้างระบบ FUSE ก็น่าลองดู
[1]: https://github.com/JelteF/dokuwikifuse
[2]: https://pypi.org/project/llfuse/
[3]: https://pypi.org/project/easyfuse/
[4]: https://github.com/JelteF/easyfuse
โดยพื้นฐานแล้ว dokuwiki เป็นชุดของไฟล์ข้อความ ดังนั้นการเมานต์ผ่าน NFS หรือแชร์ผ่าน Dropbox/Syncthing จะง่ายและมีประสิทธิภาพกว่าหรือเปล่า?
คิดว่า FUSE เป็นวิธีที่ทำให้ Makefile ระบุ directed acyclic graph บน resource ใด ๆ ก็ได้
ตัวอย่างเช่น ถ้ามีระบบไฟล์ FUSE ที่เปิดเผยสถานะของคลัสเตอร์ k8s ก็อาจทำให้เขียน operator ที่คนหัวเรียบง่ายอย่างผมเข้าถึงได้ง่ายขึ้น
อีเมลก็เช่นกัน ถ้าเปิด IMAP เป็นระบบไฟล์ แอป RAG (อย่าง gpt4all) ก็น่าจะเข้าถึงทุกอย่างได้โดยตรงไม่ใช่หรือ?
นอกเรื่องนิดหน่อย แต่เวลาเห็นบล็อกบรรยากาศยุค 90/2000 ผมมักจะเข้าไปดูหน้าโพสต์แรกเสมอ
รวมถึง gwolf.org ด้วย การได้ส่องดู ไทม์แคปซูล แบบนั้นไม่เคยทำให้ผิดหวังเลย