fix
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 @@
         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 @@
     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 @@
         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: