summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2009-07-16 11:07:31 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2009-07-16 11:07:31 +0000
commit3846394e7ad0a85a0eee3346444befa81f4425af (patch)
tree2a5fbdf198100bc6d7f92f9dca46ba62cbebad9f
parent37a90f29e8609951a18e5190d1fd3659e3aee135 (diff)
downloadfuse-3846394e7ad0a85a0eee3346444befa81f4425af.tar.gz
* Clarify how the protocol version should be negotiated between
kernel and userspace. Notably libfuse didn't correctly handle the case when the supported major versions didn't match
-rw-r--r--ChangeLog6
-rw-r--r--include/fuse_kernel.h20
-rw-r--r--lib/fuse_lowlevel.c17
3 files changed, 38 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index fc0b51f..c207b23 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2009-07-16 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Clarify how the protocol version should be negotiated between
+ kernel and userspace. Notably libfuse didn't correctly handle the
+ case when the supported major versions didn't match
+
2009-07-02 Miklos Szeredi <miklos@szeredi.hu>
* The context is extended with a 'umask' field. The umask is sent
diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h
index dac35d8..bd73630 100644
--- a/include/fuse_kernel.h
+++ b/include/fuse_kernel.h
@@ -67,6 +67,26 @@
#define __u32 uint32_t
#define __s32 int32_t
+/*
+ * Version negotiation:
+ *
+ * Both the kernel and userspace send the version they support in the
+ * INIT request and reply respectively.
+ *
+ * If the major versions match then both shall use the smallest
+ * of the two minor versions for communication.
+ *
+ * If the kernel supports a larger major version, then userspace shall
+ * reply with the major version it supports, ignore the rest of the
+ * INIT message and expect a new INIT message from the kernel with a
+ * matching major version.
+ *
+ * If the library supports a larger major version, then it shall fall
+ * back to the major protocol version sent by the kernel for
+ * communication and reply with that major version (and an arbitrary
+ * supported minor version).
+ */
+
/** Version number of this interface */
#define FUSE_KERNEL_VERSION 7
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 32b9db3..c0347b3 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -1150,7 +1150,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
(void) nodeid;
if (f->debug) {
fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor);
- if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
+ if (arg->major == 7 && arg->minor >= 6) {
fprintf(stderr, "flags=0x%08x\n", arg->flags);
fprintf(stderr, "max_readahead=0x%08x\n",
arg->max_readahead);
@@ -1161,6 +1161,10 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
f->conn.capable = 0;
f->conn.want = 0;
+ memset(&outarg, 0, sizeof(outarg));
+ outarg.major = FUSE_KERNEL_VERSION;
+ outarg.minor = FUSE_KERNEL_MINOR_VERSION;
+
if (arg->major < 7) {
fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",
arg->major, arg->minor);
@@ -1168,7 +1172,13 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
return;
}
- if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
+ if (arg->major > 7) {
+ /* Wait for a second INIT request with a 7.X version */
+ send_reply_ok(req, &outarg, sizeof(outarg));
+ return;
+ }
+
+ if (arg->minor >= 6) {
if (f->conn.async_read)
f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
if (arg->max_readahead < f->conn.max_readahead)
@@ -1211,9 +1221,6 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
if (f->op.init)
f->op.init(f->userdata, &f->conn);
- memset(&outarg, 0, sizeof(outarg));
- outarg.major = FUSE_KERNEL_VERSION;
- outarg.minor = FUSE_KERNEL_MINOR_VERSION;
if (f->conn.async_read || (f->conn.want & FUSE_CAP_ASYNC_READ))
outarg.flags |= FUSE_ASYNC_READ;
if (f->conn.want & FUSE_CAP_POSIX_LOCKS)