分类: 服务器与存储
2010-09-04 22:54:59
This page is written by CsabaHenk. At some places I will call for user input/feedback. For contact, go to my personal wiki page. (But of course, don't hesitate to improve this text without asking me.) This page also belongs to CategoryDevelopment.
The FUSE protocol follows the client/server scheme. In existing implementations, kernel plays the client role and the filesystem daemon plays the server role. (It would be possible, eg., to have userspace clients, too, which would act as proxies for the kernel, either on local or remote machines; however, the protocol as such is not portable between platforms, as it refers to things like errnos which vary from platform to platform.)
Communication goes as follows: there is a fixed set of operations. These can be grouped into two sets: operations for which messaging follows a
client --[query]--> server --[answer]--> client
scheme, and operations for which messaging follows a
client --[query]--> server
scheme. As of writing this, almost all operations follow the former scheme; AFAIK FUSE_FORGET
is the only one which uses the second one. (TODO: check if this is still valid; what's the case with the newish FUSE_INTERRUPT
message?)
Queries and answers have a message ID attribute. The server is expected to preserve the message ID when answering a query. (Message ID generation is up to the client. Usually the client will want to achieve that it can uniquely identify answers. In practice, this implies that message IDs should be unique among ongoing operations, but need not be globally unique.)
Each query and answer is self contained, there is no packet fragmentation like in TCP/IP. The whole FUSE session starts with a FUSE_INIT
operation which (among other purposes) is used for negotiating the size limits of messages (in earlier versions of the protocol these limits were constants but now they can be effectively negotiated).
Each query starts with a fuse_in_header structure, and each answer starts with a fuse_out_header structure. This is optionally followed then by some other data. The above mentioned message IDs are stored in the unique
field of these structures.
I won't give here a precise description of the formats of the queries and answers, but I do give some pointers which can help you in finding them out.
The operation set and the structures involved in FUSE communication is described in the fuse_kernel.h file.
Johan Rydberg has put together a very readable description of the protocol (out of wiki; also covers semantic aspects). It is somewhat out of date (not unlike the other resources...)
Another thing to take a look at is the fuse_body_audit() function of the FreeBSD FUSE kernel module. This function checks if answers are properly formatted, so reading this code can reveal you how answers for the certain operations look like. (As of writing this, it doesn't reflects the latest revision of the protocol, but it will get updated in the close future.) (Note that the Linux FUSE kernel module, albeit it's the de facto standard client implementation, doesn't have such a central place for checking answer format, so it would be harder to find it out from that code.)
Yet other things are my YAML specifications. (These are part of a ruby FUSE client/server skeleton which was used for debugging the protocol implementation for FreeBSD.)
Here are the specs for the queries. This is available as a part of the fuse4bsd code, but for the sake of completeness, I also inline it.
--- :opcodes: FUSE_MKNOD: 8 FUSE_OPEN: 14 FUSE_SETLKW: 33 FUSE_LISTXATTR: 23 FUSE_RELEASE: 18 FUSE_READ: 15 FUSE_LINK: 13 FUSE_SETLK: 32 FUSE_FSYNC: 20 FUSE_SYMLINK: 6 FUSE_READLINK: 5 FUSE_RELEASEDIR: 29 FUSE_FORGET: 2 FUSE_GETLK: 31 FUSE_OPENDIR: 27 FUSE_WRITE: 16 FUSE_GETXATTR: 22 FUSE_LOOKUP: 1 FUSE_READDIR: 28 FUSE_INIT: 26 FUSE_REMOVEXATTR: 24 FUSE_SETXATTR: 21 FUSE_STATFS: 17 FUSE_RMDIR: 11 FUSE_GETATTR: 3 FUSE_FSYNCDIR: 30 FUSE_FLUSH: 25 FUSE_RENAME: 12 FUSE_UNLINK: 10 FUSE_MKDIR: 9 FUSE_SETATTR: 4 :typemap: FUSE_MKNOD: - fuse_mknod_in - char * FUSE_OPEN: fuse_open_in FUSE_SETLKW: fuse_lk_in_out FUSE_LISTXATTR: fuse_getxattr_in FUSE_READ: fuse_read_in FUSE_RELEASE: fuse_release_in FUSE_LINK: - fuse_link_in - char * FUSE_SETLK: fuse_lk_in_out FUSE_FSYNC: fuse_fsync_in FUSE_SYMLINK: char * FUSE_READLINK: FUSE_RELEASEDIR: fuse_release_in FUSE_FORGET: fuse_forget_in FUSE_GETLK: fuse_lk_in_out FUSE_OPENDIR: fuse_open_in FUSE_WRITE: - fuse_write_in - char * FUSE_GETXATTR: - fuse_getxattr_in - char * FUSE_LOOKUP: char * FUSE_READDIR: fuse_read_in FUSE_INIT: fuse_init_in_out FUSE_REMOVEXATTR: char * FUSE_SETXATTR: - fuse_setxattr_in - char * FUSE_STATFS: FUSE_RMDIR: char * FUSE_GETATTR: FUSE_FSYNCDIR: fuse_fsync_in FUSE_FLUSH: fuse_flush_in FUSE_RENAME: - fuse_rename_in - char * FUSE_UNLINK: char * FUSE_MKDIR: - fuse_mkdir_in - char * FUSE_SETATTR: fuse_setattr_in :structs_raw: fuse_getxattr_in: - "\t__u32\tsize;\n" - "\t__u32\tpadding;\n" fuse_flush_in: - "\t__u64\tfh;\n" - "\t__u32\tflush_flags;\n" - "\t__u32\tpadding;\n" fuse_rename_in: - "\t__u64\tnewdir;\n" fuse_write_in: - "\t__u64\tfh;\n" - "\t__u64\toffset;\n" - "\t__u32\tsize;\n" - "\t__u32\twrite_flags;\n" fuse_forget_in: - "\t__u64\tnlookup;\n" fuse_lk_in_out: - "\tstruct fuse_file_lock lk;\n" fuse_setattr_in: - "\t__u32\tvalid;\n" - "\t__u32\tpadding;\n" - "\tstruct fuse_attr attr;\n" fuse_fsync_in: - "\t__u64\tfh;\n" - "\t__u32\tfsync_flags;\n" - "\t__u32\tpadding;\n" fuse_link_in: - "\t__u64\toldnodeid;\n" fuse_file_lock: - "\t__u64\tstart;\n" - "\t__u64\tend;\n" - "\t__u64\towner;\n" - "\t__u32\tpid;\n" - "\t__u32\ttype;\n" fuse_open_in: - "\t__u32\tflags;\n" - "\t__u32\tpadding;\n" fuse_mknod_in: - "\t__u32\tmode;\n" - "\t__u32\trdev;\n" fuse_init_in_out: - "\t__u32\tmajor;\n" - "\t__u32\tminor;\n" fuse_mkdir_in: - "\t__u32\tmode;\n" - "\t__u32\tpadding;\n" fuse_attr: - "\t__u64\tino;\n" - "\t__u64\tsize;\n" - "\t__u64\tblocks;\n" - "\t__u64\tatime;\n" - "\t__u64\tmtime;\n" - "\t__u64\tctime;\n" - "\t__u32\tatimensec;\n" - "\t__u32\tmtimensec;\n" - "\t__u32\tctimensec;\n" - "\t__u32\tmode;\n" - "\t__u32\tnlink;\n" - "\t__u32\tuid;\n" - "\t__u32\tgid;\n" - "\t__u32\trdev;\n" fuse_in_header: - "\t__u32\tlen;\n" - "\t__u32\topcode;\n" - "\t__u64\tunique;\n" - "\t__u64\tnodeid;\n" - "\t__u32\tuid;\n" - "\t__u32\tgid;\n" - "\t__u32\tpid;\n" - "\t__u32\tpadding;\n" fuse_setxattr_in: - "\t__u32\tsize;\n" - "\t__u32\tflags;\n" fuse_read_in: - "\t__u64\tfh;\n" - "\t__u64\toffset;\n" - "\t__u32\tsize;\n" - "\t__u32\tpadding;\n" fuse_release_in: - "\t__u64\tfh;\n" - "\t__u32\tflags;\n" - "\t__u32\tpadding;\n" :zipcodes: false: L char *: a* :u32: L :s32: l :u64: q
And the other YAML which describes the format of the answers:
--- :opcodes: FUSE_MKNOD: 8 FUSE_OPEN: 14 FUSE_LINK: 13 FUSE_READ: 15 FUSE_RELEASE: 18 FUSE_LISTXATTR: 23 FUSE_SETLKW: 33 FUSE_READLINK: 5 FUSE_SYMLINK: 6 FUSE_FSYNC: 20 FUSE_SETLK: 32 FUSE_FORGET: 2 FUSE_RELEASEDIR: 29 FUSE_WRITE: 16 FUSE_OPENDIR: 27 FUSE_GETLK: 31 FUSE_LOOKUP: 1 FUSE_GETXATTR: 22 FUSE_REMOVEXATTR: 24 FUSE_INIT: 26 FUSE_READDIR: 28 FUSE_GETATTR: 3 FUSE_RMDIR: 11 FUSE_STATFS: 17 FUSE_SETXATTR: 21 FUSE_SETATTR: 4 FUSE_MKDIR: 9 FUSE_UNLINK: 10 FUSE_RENAME: 12 FUSE_FLUSH: 25 FUSE_FSYNCDIR: 30 :structs_raw: fuse_getxattr_out: - "\t__u32\tsize;\n" - "\t__u32\tpadding;\n" fuse_getxattr_in: - "\t__u32\tsize;\n" - "\t__u32\tpadding;\n" fuse_flush_in: - "\t__u64\tfh;\n" - "\t__u32\tflush_flags;\n" - "\t__u32\tpadding;\n" fuse_rename_in: - "\t__u64\tnewdir;\n" fuse_access_in: - "\t__u32\tmask;\n" - "\t__u32\tpadding;\n" fuse_write_in: - "\t__u64\tfh;\n" - "\t__u64\toffset;\n" - "\t__u32\tsize;\n" - "\t__u32\twrite_flags;\n" fuse_forget_in: - "\t__u64\tnlookup;\n" fuse_entry_out: - "\t__u64\tnodeid;\n" - "\t__u64\tgeneration;\n" - "\t__u64\tentry_valid;\n" - "\t__u64\tattr_valid;\n" - "\t__u32\tentry_valid_nsec;\n" - "\t__u32\tattr_valid_nsec;\n" - "\tstruct fuse_attr attr;\n" fuse_lk_in_out: - "\tstruct fuse_file_lock lk;\n" fuse_setattr_in: - "\t__u32\tvalid;\n" - "\t__u32\tpadding;\n" - "\tstruct fuse_attr attr;\n" fuse_init_in_out: - "\t__u32\tmajor;\n" - "\t__u32\tminor;\n" fuse_fsync_in: - "\t__u64\tfh;\n" - "\t__u32\tfsync_flags;\n" - "\t__u32\tpadding;\n" fuse_write_out: - "\t__u32\tsize;\n" - "\t__u32\tpadding;\n" fuse_open_out: - "\t__u64\tfh;\n" - "\t__u32\topen_flags;\n" - "\t__u32\tpadding;\n" fuse_link_in: - "\t__u64\toldnodeid;\n" fuse_file_lock: - "\t__u64\tstart;\n" - "\t__u64\tend;\n" - "\t__u64\towner;\n" - "\t__u32\tpid;\n" - "\t__u32\ttype;\n" fuse_dirent: - "\t__u64\tino;\n" - "\t__u64\toff;\n" - "\t__u32\tnamelen;\n" - "\t__u32\ttype;\n" - "\tchar name[[0]];\n" fuse_out_header: - "\t__u32\tlen;\n" - "\t__s32\terror;\n" - "\t__u64\tunique;\n" fuse_open_in: - "\t__u32\tflags;\n" - "\t__u32\tpadding;\n" fuse_statfs_out: - "\tstruct fuse_kstatfs st;\n" fuse_mknod_in: - "\t__u32\tmode;\n" - "\t__u32\trdev;\n" fuse_kstatfs: - "\t__u64\tblocks;\n" - "\t__u64\tbfree;\n" - "\t__u64\tbavail;\n" - "\t__u64\tfiles;\n" - "\t__u64\tffree;\n" - "\t__u32\tbsize;\n" - "\t__u32\tnamelen;\n" fuse_mkdir_in: - "\t__u32\tmode;\n" - "\t__u32\tpadding;\n" fuse_attr_out: - "\t__u64\tattr_valid;\n" - "\t__u32\tattr_valid_nsec;\n" - "\t__u32\tdummy;\n" - "\tstruct fuse_attr attr;\n" fuse_attr: - "\t__u64\tino;\n" - "\t__u64\tsize;\n" - "\t__u64\tblocks;\n" - "\t__u64\tatime;\n" - "\t__u64\tmtime;\n" - "\t__u64\tctime;\n" - "\t__u32\tatimensec;\n" - "\t__u32\tmtimensec;\n" - "\t__u32\tctimensec;\n" - "\t__u32\tmode;\n" - "\t__u32\tnlink;\n" - "\t__u32\tuid;\n" - "\t__u32\tgid;\n" - "\t__u32\trdev;\n" fuse_in_header: - "\t__u32\tlen;\n" - "\t__u32\topcode;\n" - "\t__u64\tunique;\n" - "\t__u64\tnodeid;\n" - "\t__u32\tuid;\n" - "\t__u32\tgid;\n" - "\t__u32\tpid;\n" - "\t__u32\tpadding;\n" fuse_setxattr_in: - "\t__u32\tsize;\n" - "\t__u32\tflags;\n" fuse_read_in: - "\t__u64\tfh;\n" - "\t__u64\toffset;\n" - "\t__u32\tsize;\n" - "\t__u32\tpadding;\n" fuse_release_in: - "\t__u64\tfh;\n" - "\t__u32\tflags;\n" - "\t__u32\tpadding;\n" :typemap: FUSE_MKNOD: fuse_entry_out FUSE_OPEN: fuse_open_out FUSE_SETLKW: false FUSE_RELEASE: 0 FUSE_READ: char * FUSE_LISTXATTR: false FUSE_LINK: fuse_entry_out FUSE_SYMLINK: fuse_entry_out FUSE_SETLK: false FUSE_READLINK: char * FUSE_FSYNC: 0 FUSE_RELEASEDIR: 0 FUSE_FORGET: -1 FUSE_WRITE: fuse_write_out FUSE_OPENDIR: fuse_open_out FUSE_GETLK: false FUSE_LOOKUP: fuse_entry_out FUSE_GETXATTR: fuse_getxattr_out FUSE_REMOVEXATTR: FUSE_READDIR: char * FUSE_INIT: fuse_init_in_out FUSE_STATFS: fuse_statfs_out FUSE_SETXATTR: false FUSE_RMDIR: 0 FUSE_GETATTR: fuse_attr_out FUSE_UNLINK: 0 FUSE_SETATTR: fuse_attr_out FUSE_RENAME: 0 FUSE_MKDIR: fuse_entry_out FUSE_FSYNCDIR: 0 FUSE_FLUSH: 0 :zipcodes: :u32: L char *: a* false: L :s32: l :u64: q
The protocol version they describe is a bit old, but at least, you can see they include fuse_kernel.h
in a semi-parsed format, so you can find out what version is exactly referred to and what has changed since then (would be good if you updated them and send me the updated versions).
The most interesting parts are the typemap
sections. These describe the format of the query/answer body (that is, the part which comes after the respective headers).
Eg. the entry:
FUSE_LINK: - fuse_link_in - char *
tells you that the body of FUSE_LINK consists of a fuse_link_in structure and a string.
FUSE_SETLKW: false
This means that the body information for this operation is missing (would be good if you found out and told me about that).
FUSE_RELEASE: 0
This means that there is no body (message consists only of a header).
FUSE_FORGET: -1
This refers to an operation which follows the unanswered query scheme.
Note that some body descriptions are (accidentally) truncated: eg. the for the FUSE_RENAME
query we have
FUSE_RENAME: - fuse_rename_in - char *
while it should be
FUSE_RENAME: - fuse_rename_in - char * - char *
Would be good if you could find other occurrences of this bug. Please report them if you find one.
I present the YAMLs as they looked like when I dealt with them last time. The protocol should be thoroughly researched before posting improved versions, so I didn't applied random fixes like the above.
原文链接:
chinaunix网友2010-09-06 14:41:21
Download More than 1000 free IT eBooks: http://free-ebooks.appspot.com