fuse - جهاز "نظام ملفات في مساحة المستخدم" (FUSE)
ملخص
#include <linux/fuse.h>
الوصف
هذا الجهاز هو الواجهة الرئيسية بين برنامج تشغيل نظام الملفات FUSE وعملية في مساحة المستخدم ترغب في توفير نظام الملفات (المشار إليه في بقية هذه الصفحة كعملية "نظام الملفات"). تهدف هذه الصفحة إلى أولئك المهتمين بفهم واجهة النواة نفسها. قد يرغب أولئك الذين يقومون بتنفيذ نظام ملفات FUSE في استخدام مكتبة في مساحة المستخدم مثل libfuse التي تجرّد الواجهة منخفضة المستوى.
في جوهره، FUSE هو بروتوكول عميل-خادم بسيط، حيث تكون نواة Linux هي العميل والعملية هي الخادم. بعد الحصول على واصف ملف لهذا الجهاز، يمكن للعملية قراءة (2) الطلبات من واصف الملف هذا ومن المتوقع أن تكتب (2) ردودها مرة أخرى. من المهم ملاحظة أن واصف الملف مرتبط بنظام ملفات FUSE فريد. على وجه التحديد، فإن فتح نسخة ثانية من هذا الجهاز لن يسمح بالوصول إلى الموارد التي تم إنشاؤها من خلال واصف الملف الأول (والعكس صحيح).
البروتوكول الأساسي
تبدأ كل رسالة يتم قراءتها بواسطة العملية برأس موصوف بالهيكل التالي:
struct fuse_in_header {
uint32_t len; /* الحجم الإجمالي للبيانات،
بما في ذلك هذا الرأس */
uint32_t opcode; /* نوع العملية (انظر أدناه) */
uint64_t unique; /* معرف فريد لهذا الطلب */
uint64_t nodeid; /* مُعرّف كائن نظام الملفات
الذي يتم تشغيله */
uint32_t uid; /* مُعرّف المستخدم للعملية الطالبة */
uint32_t gid; /* مُعرّف المجموعة للعملية الطالبة */
uint32_t pid; /* مُعرّف العملية للعملية الطالبة */
uint32_t padding;
};
يتبع الرأس جزء بيانات متغير الحجم (الذي قد يكون فارغًا) خاص بالعملية المطلوبة (يتم الإشارة إلى العملية المطلوبة بواسطة opcode).
يجب أن تقوم العملية بعد ذلك بمعالجة الطلب - وإذا لزم الأمر - إرسال رد عن طريق إجراء كتابة (2) إلى
واصف الملف. يجب أن تبدأ جميع الردود بالرأس التالي:
struct fuse_out_header {
uint32_t len; /* الحجم الإجمالي للبيانات المكتوبة
إلى واصف الملف */
int32_t error; /* أي خطأ حدث (0 إذا لم يكن هناك أي خطأ) */
uint64_t unique; /* القيمة من
الطلب المقابل */
};
يتبع هذا الرأس أيضًا (جزء بيانات متغير الحجم المحتمل أن يكون فارغًا) اعتمادًا على الطلب الذي تم تنفيذه. ومع ذلك، إذا كان الرد عبارة عن رد خطأ (أي تم تعيين الخطأ)، فلن يتم إرسال أي بيانات إضافية، بغض النظر عن الطلب.
الرسائل المتبادلة
يجب أن يحتوي هذا القسم على وثائق لكل رسالة في البروتوكول. هذه الصفحة اليدوية غير مكتملة حاليًا، لذلك لا يتم توثيق جميع الرسائل. لكل رسالة، يتم أولاً إعطاء الهيكل الذي ترسله النواة، يليه وصف لدلالات الرسالة.
FUSE_INIT
struct fuse_init_in {
uint32_t major;
uint32_t minor;
uint32_t max_readahead; /* منذ الإصدار 7.6 من البروتوكول */
uint32_t flags; /* منذ الإصدار 7.6 من البروتوكول */
};
هذا هو أول طلب ترسله النواة إلى البرنامج. يتم استخدامه للتفاوض بشأن إصدار البروتوكول ومعلمات نظام الملفات الأخرى. لاحظ أن إصدار البروتوكول قد يؤثر على تخطيط أي هيكل في البروتوكول (بما في ذلك هذا الهيكل). يجب على البرنامج تذكر الإصدار والعلامات المتفَق عليها لكل جلسة. اعتبارًا من كتابة هذه الصفحة اليدوية، فإن أعلى إصدار من البروتوكول تدعمه النواة هو 7.26.
يجب أن يكون المستخدمون على علم بأن الأوصاف الموجودة في هذه الصفحة اليدوية قد تكون غير كاملة أو غير صحيحة للإصدارات القديمة أو الأحدث من البروتوكول.
يحتوي الرد على هذا الطلب على التنسيق التالي:
struct fuse_init_out {
uint32_t major;
uint32_t minor;
uint32_t max_readahead; /* منذ الإصدار 7.6 */
uint32_t flags; /* منذ الإصدار 7.6؛ تم تقديم بعض بتات العلامات لاحقًا */
uint16_t max_background; /* منذ الإصدار 7.13 */
uint16_t congestion_threshold; /* منذ الإصدار 7.13 */
uint32_t max_write; /* منذ الإصدار 7.5 */
uint32_t time_gran; /* منذ الإصدار 7.6 */
uint32_t unused[9];
};
إذا كان إصدار النواة الرئيسي المدعوم أكبر من الإصدار الرئيسي المدعوم بواسطة البرنامج، فيجب أن يتكون الرد من uint32_t major فقط (بعد الرأس المعتاد)، مما يشير إلى أكبر إصدار رئيسي مدعوم بواسطة البرنامج. ثم سترسل النواة طلب FUSE_INIT جديد يتوافق مع الإصدار الأقدم. في الحالة المعاكسة، يجب على البرنامج أن ينتقل بهدوء إلى الإصدار الرئيسي للنواة.
يعتبر الإصدار الثانوي المتفَق عليه هو الحد الأدنى من الإصدارات الثانوية التي يوفرها البرنامج والنواة، ويجب على الطرفين استخدام البروتوكول المقابل لهذا الإصدار الثانوي.
FUSE_GETATTR
struct fuse_getattr_in {
uint32_t getattr_flags;
uint32_t dummy;
uint64_t fh; /* يتم تعيينه فقط إذا
(getattr_flags & FUSE_GETATTR_FH)
};
العملية المطلوبة هي حساب السمات المراد إرجاعها بواسطة stat(2) والعمليات المماثلة لنظام الملفات المحدد. يتم تحديد الكائن الذي يجب حساب سماته إما بواسطة header->nodeid أو، إذا تم تعيين علامة FUSE_GETATTR_FH، بواسطة معرّف الملف fh. الحالة الأخيرة من العملية مماثلة لـ fstat(2).
لأسباب تتعلق بالأداء، يمكن تخزين هذه السمات في ذاكرة التخزين المؤقت للنواة لفترة زمنية محددة. طالما لم يتم تجاوز مهلة ذاكرة التخزين المؤقت، سيتم تقديم السمات من ذاكرة التخزين المؤقت ولن تتسبب في طلبات FUSE_GETATTR إضافية.
يجب بعد ذلك إرجاع السمات المحسوبة والمهلة الزمنية المطلوبة لذاكرة التخزين المؤقت في الهيكل التالي:
struct fuse_attr_out {
/* مدة صلاحية السمات (بالثواني والنانوثواني) */
uint64_t attr_valid;
uint32_t attr_valid_nsec;
uint32_t dummy;
struct fuse_attr {
uint64_t ino;
uint64_t size;
uint64_t blocks;
uint64_t atime;
uint64_t mtime;
uint64_t ctime;
uint32_t atimensec;
uint32_t mtimensec;
uint32_t ctimensec;
uint32_t mode;
uint32_t nlink;
uint32_t uid;
uint32_t gid;
uint32_t rdev;
uint32_t blksize;
uint32_t padding;
} attr;
};
FUSE_ACCESS
struct fuse_access_in {
uint32_t mask;
uint32_t padding;
};
إذا لم يتم استخدام خيار التثبيت default_permissions، فيمكن استخدام هذا الطلب للتحقق من الأذونات. لا يُتوقع أي بيانات رد، ولكن يمكن الإشارة إلى الأخطاء بالطريقة المعتادة عن طريق تعيين حقل الخطأ في رأس الرد (على وجه الخصوص، يمكن الإشارة إلى أخطاء رفض الوصول عن طريق إرجاع -EACCES).
FUSE_OPEN
FUSE_OPENDIR
struct fuse_open_in {
uint32_t flags; /* العلامات التي تم تمريرها إلى الدالة `open(2)` */
uint32_t unused;
};
العملية المطلوبة هي فتح العقدة المشار إليها بواسطة header->nodeid. ستعتمد الدلالات الدقيقة لما يعنيه هذا على نظام الملفات الذي يتم تنفيذه. ومع ذلك، على الأقل، يجب أن يتحقق نظام الملفات من أن العلامات المطلوبة صالحة للمورد المحدد، ثم يرسل ردًا بالتنسيق التالي:
struct fuse_open_out {
uint64_t fh;
uint32_t open_flags;
uint32_t padding;
};
الحقل `fh` هو معرف معتم سيستخدمه النواة للإشارة إلى هذا المورد. الحقل `open_flags` هو قناع بتي لأي عدد من العلامات التي تشير إلى خصائص معينة لهذا واصف الملف للنواة:
FOPEN_DIRECT_IO تجاوز ذاكرة التخزين المؤقت للصفحات لهذا الملف المفتوح.
FOPEN_KEEP_CACHE لا تقم بإبطال ذاكرة البيانات المؤقتة عند فتح الملف.
FOPEN_NONSEEKABLE الملف غير قابل للبحث.
FUSE_READ
FUSE_READDIR
struct fuse_read_in {
uint64_t fh;
uint64_t offset;
uint32_t size;
uint32_t read_flags;
uint64_t lock_owner;
uint32_t flags;
uint32_t padding;
};
الإجراء المطلوب هو قراءة ما يصل إلى size بايت من الملف أو الدليل، بدءًا من offset. يجب إرجاع البايتات مباشرة بعد رأس الرد المعتاد.
FUSE_INTERRUPT
struct fuse_interrupt_in {
uint64_t unique;
};
الإجراء المطلوب هو إلغاء العملية المعلقة التي تم الإشارة إليها بواسطة unique. لا يتطلب هذا الطلب أي استجابة. ومع ذلك، فإن استلام هذه الرسالة لا يلغي من تلقاء نفسه العملية المشار إليها. ستظل النواة تتوقع ردًا على العملية المذكورة (على سبيل المثال، خطأ EINTR أو قراءة قصيرة). لن يتم إصدار طلب FUSE_INTERRUPT واحد على الأكثر لعملية معينة. بعد إصدار العملية المذكورة، ستنتظر النواة بشكل غير قابل للمقاطعة حتى اكتمال العملية المشار إليها.
FUSE_LOOKUP
يتبع مباشرة رأس الطلب اسم الملف المراد البحث عنه في الدليل المشار إليه بواسطة header->nodeid. الرد المتوقع هو:
struct fuse_entry_out {
uint64_t nodeid; /* معرف العقدة */
uint64_t generation; /* جيل العقدة */
uint64_t entry_valid;
uint64_t attr_valid;
uint32_t entry_valid_nsec;
uint32_t attr_valid_nsec;
struct fuse_attr attr;
};
يجب أن يكون مزيج nodeid و generation فريدًا طوال عمر نظام الملفات.
تفسير المهلات و attr هو كما هو الحال في FUSE_GETATTR.
FUSE_FLUSH
struct fuse_flush_in {
uint64_t fh;
uint32_t unused;
uint32_t padding;
uint64_t lock_owner;
};
الإجراء المطلوب هو إفراغ أي تغييرات معلقة إلى مُعامل الملف المحدد. لا يُتوقع أي بيانات رد. ومع ذلك، لا يزال من الضروري إصدار رسالة رد فارغة بمجرد اكتمال عملية الإفراغ.
FUSE_RELEASE
FUSE_RELEASEDIR
struct fuse_release_in {
uint64_t fh;
uint32_t flags;
uint32_t release_flags;
uint64_t lock_owner;
};
هذه هي العمليات العكسية لـ FUSE_OPEN و FUSE_OPENDIR على التوالي. يمكن للبرنامج الآن تحرير أي موارد مرتبطة بمعرف الملف fh حيث لن يشير النواة إليه بعد الآن. لا توجد بيانات رد مرتبطة بهذا الطلب، ولكن لا يزال من الضروري إصدار رد بمجرد معالجة الطلب بالكامل.
FUSE_STATFS
تقوم هذه العملية بتنفيذ statfs(2) لهذا نظام الملفات. لا توجد بيانات إدخال مرتبطة بهذا الطلب. بيانات الرد المتوقعة لها البنية التالية:
struct fuse_kstatfs {
uint64_t blocks;
uint64_t bfree;
uint64_t bavail;
uint64_t files;
uint64_t ffree;
uint32_t bsize;
uint32_t namelen;
uint32_t frsize;
uint32_t padding;
uint32_t spare[6];
};
struct fuse_statfs_out {
struct fuse_kstatfs st;
};
للحصول على تفسير لهذه الحقول، راجع statfs(2).
الأخطاء
E2BIG يتم إرجاعها من عمليات `read(2)` عندما يكون طلب النواة كبيرًا جدًا للذاكرة المؤقتة المقدمة وكان الطلب `FUSE_SETXATTR`.
EINVAL يتم إرجاعها من `write(2)` إذا فشل التحقق من صحة الرد. لن يتم اكتشاف جميع الأخطاء في الردود بواسطة هذا التحقق. ومع ذلك، يتم اكتشاف الأخطاء الأساسية، مثل الردود القصيرة أو قيمة فريدة غير صحيحة.
EIO يتم إرجاعها من عمليات `read(2)` عندما يكون طلب النواة كبيرًا جدًا للذاكرة المؤقتة المقدمة.
ملاحظة: هناك طرق مختلفة يمكن أن يؤدي فيها الاستخدام غير الصحيح لهذه الواجهات إلى فشل العمليات على الملفات والدلائل في نظام الملفات المقدم مع `EIO`. من بين الاستخدامات غير الصحيحة المحتملة:
تغيير الوضع و `S_IFMT` لعقدة تم الإبلاغ عنها للنواة مسبقًا؛ أو
إعطاء ردود للنواة أقصر مما كان متوقعًا.
ENODEV يتم إرجاعها من `read(2)` و `write(2)` إذا تم إلغاء تحميل نظام ملفات FUSE.
EPERM يتم إرجاعها من العمليات على واصف ملف `/dev/fuse` الذي لم يتم تركيبه.
المعايير
لينكس.
ملاحظات
لم يتم توثيق الرسائل التالية في صفحة الدليل هذه بعد:
FUSE_BATCH_FORGET
FUSE_BMAP
FUSE_CREATE
FUSE_DESTROY
FUSE_FALLOCATE
FUSE_FORGET
FUSE_FSYNC
FUSE_FSYNCDIR
FUSE_GETLK
FUSE_GETXATTR
FUSE_IOCTL
FUSE_LINK
FUSE_LISTXATTR
FUSE_LSEEK
FUSE_MKDIR
FUSE_MKNOD
FUSE_NOTIFY_REPLY
FUSE_POLL
FUSE_READDIRPLUS
FUSE_READLINK
FUSE_REMOVEXATTR
FUSE_RENAME
FUSE_RENAME2
FUSE_RMDIR
FUSE_SETATTR
FUSE_SETLK
FUSE_SETLKW
FUSE_SYMLINK
FUSE_UNLINK
FUSE_WRITE
انظر أيضاً
fusermount(1)، mount.fuse(8)