aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse_kern_chan.c6
-rw-r--r--lib/fuse_loop_mt.c2
-rw-r--r--lib/fuse_lowlevel.c41
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: