Chinaunix首页 | 论坛 | 博客
  • 博客访问: 200635
  • 博文数量: 55
  • 博客积分: 2330
  • 博客等级: 大尉
  • 技术积分: 504
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-20 22:55
文章分类

全部博文(55)

文章存档

2013年(6)

2012年(7)

2011年(7)

2010年(35)

我的朋友

分类: 服务器与存储

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.



原文链接:

阅读(995) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-09-06 14:41:21

Download More than 1000 free IT eBooks: http://free-ebooks.appspot.com