diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fuse_kern_chan.c | 6 | ||||
-rw-r--r-- | lib/fuse_loop_mt.c | 2 | ||||
-rw-r--r-- | lib/fuse_lowlevel.c | 41 |
3 files changed, 43 insertions, 6 deletions
diff --git a/lib/fuse_kern_chan.c b/lib/fuse_kern_chan.c index d2999c5..fbe3943 100644 --- a/lib/fuse_kern_chan.c +++ b/lib/fuse_kern_chan.c @@ -64,6 +64,8 @@ static void fuse_kern_chan_destroy(struct fuse_chan *ch) close(fuse_chan_fd(ch)); } +#define MIN_BUFSIZE 0x21000 + struct fuse_chan *fuse_kern_chan_new(int fd) { struct fuse_chan_ops op = { @@ -71,5 +73,7 @@ struct fuse_chan *fuse_kern_chan_new(int fd) .send = fuse_kern_chan_send, .destroy = fuse_kern_chan_destroy, }; - return fuse_chan_new(&op, fd, FUSE_MAX_IN, NULL); + size_t bufsize = getpagesize() + 0x1000; + bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize; + return fuse_chan_new(&op, fd, bufsize, NULL); } diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c index 37f0922..3566c60 100644 --- a/lib/fuse_loop_mt.c +++ b/lib/fuse_loop_mt.c @@ -155,7 +155,7 @@ int fuse_session_loop_mt(struct fuse_session *se) memset(w, 0, sizeof(struct fuse_worker)); w->se = se; w->prevch = fuse_session_next_chan(se, NULL); - w->ch = fuse_chan_new(&cop, -1, 0, w); + w->ch = fuse_chan_new(&cop, -1, fuse_chan_bufsize(w->prevch), w); if (w->ch == NULL) { free(w); return -1; diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 3cc49f0..0787368 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -19,6 +19,17 @@ #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) +/* PATH_MAX is 4k on Linux, but I don't dare to define it to PATH_MAX, + because it may be much larger on other systems */ +#define MIN_SYMLINK 0x1000 + +/* Generous 4k overhead for headers, includes room for xattr name + (XATTR_NAME_MAX = 255) */ +#define HEADER_OVERHEAD 0x1000 + +/* 8k, the same as the old FUSE_MAX_IN constant */ +#define MIN_BUFFER_SIZE (MIN_SYMLINK + HEADER_OVERHEAD) + struct fuse_ll { unsigned int debug : 1; unsigned int allow_root : 1; @@ -683,10 +694,11 @@ static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name) fuse_reply_err(req, ENOSYS); } -static void do_init(fuse_req_t req, struct fuse_init_in_out *arg) +static void do_init(fuse_req_t req, struct fuse_init_in *arg) { - struct fuse_init_in_out outarg; + struct fuse_init_out outarg; struct fuse_ll *f = req->f; + size_t bufsize = fuse_chan_bufsize(req->ch); if (f->debug) { printf("INIT: %u.%u\n", arg->major, arg->minor); @@ -699,16 +711,37 @@ static void do_init(fuse_req_t req, struct fuse_init_in_out *arg) f->major = FUSE_KERNEL_VERSION; f->minor = arg->minor; + if (bufsize < MIN_BUFFER_SIZE) { + fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize); + bufsize = MIN_BUFFER_SIZE; + } + + bufsize -= HEADER_OVERHEAD; + memset(&outarg, 0, sizeof(outarg)); outarg.major = f->major; outarg.minor = FUSE_KERNEL_MINOR_VERSION; + /* The calculated limits may be oversized, but because of the + limits in VFS names and symlinks are never larger than PATH_MAX - 1 + and xattr values never larger than XATTR_SIZE_MAX */ + + /* Max two names per request */ + outarg.symlink_max = outarg.name_max = bufsize / 2; + /* But if buffer is small, give more room to link name */ + if (outarg.symlink_max < MIN_SYMLINK) { + outarg.symlink_max = MIN_SYMLINK; + /* Borrow from header overhead for the SYMLINK operation */ + outarg.name_max = HEADER_OVERHEAD / 4; + } + outarg.xattr_size_max = outarg.max_write = bufsize; + if (f->debug) { printf(" INIT: %u.%u\n", outarg.major, outarg.minor); fflush(stdout); } - send_reply_ok(req, &outarg, sizeof(outarg)); + send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg)); } void *fuse_req_userdata(fuse_req_t req) @@ -759,7 +792,7 @@ static void fuse_ll_process(void *data, const char *buf, size_t len, fuse_reply_err(req, EACCES); } else switch (in->opcode) { case FUSE_INIT: - do_init(req, (struct fuse_init_in_out *) inarg); + do_init(req, (struct fuse_init_in *) inarg); break; case FUSE_LOOKUP: |