From 3846394e7ad0a85a0eee3346444befa81f4425af Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 16 Jul 2009 11:07:31 +0000 Subject: * 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 --- ChangeLog | 6 ++++++ include/fuse_kernel.h | 20 ++++++++++++++++++++ lib/fuse_lowlevel.c | 17 ++++++++++++----- 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 + + * 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 * 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) -- cgit v1.2.1