f3781e
From 5100bdc814435a1222fef6438cebcd81a3de6c73 Mon Sep 17 00:00:00 2001
f3781e
From: scosu <mpargmann@allfex.org>
f3781e
Date: Thu, 13 Jun 2019 13:59:10 +0200
f3781e
Subject: [PATCH 2/4] fuse_lowlevel: Add max_pages support (#384)
f3781e
f3781e
Starting with kernel version 4.20 fuse supports a new property
f3781e
'max_pages' which is the maximum number of pages that can be used per
f3781e
request. This can be set via an argument during initialization.
f3781e
This new property allows writes to be larger than 128k.
f3781e
f3781e
This patch sets the property if the matching capability is set
f3781e
(FUSE_MAX_PAGES). It will also set max_write to 1MiB. Filesystems have
f3781e
the possibility to decrease this size by setting max_write to a smaller
f3781e
size. The max_pages and bufsize fields are adjusted accordingly.
f3781e
f3781e
Cc: Constantine Shulyupin <const@MakeLinux.com>
f3781e
Signed-off-by: Markus Pargmann <scosu@quobyte.com>
f3781e
(cherry picked from commit 027d0d17c8a4605109f09d9c988e255b64a2c19a)
f3781e
Signed-off-by: Pavel Reichl <preichl@redhat.com>
f3781e
---
f3781e
 ChangeLog.rst       |  7 +++++++
f3781e
 lib/fuse_i.h        |  6 ++++++
f3781e
 lib/fuse_lowlevel.c | 30 +++++++++++++++++++++---------
f3781e
 3 files changed, 34 insertions(+), 9 deletions(-)
f3781e
f3781e
diff --git a/ChangeLog.rst b/ChangeLog.rst
f3781e
index 8ea9397..411cd4a 100644
f3781e
--- a/ChangeLog.rst
f3781e
+++ b/ChangeLog.rst
f3781e
@@ -1,6 +1,13 @@
f3781e
 libfuse 3.3.0 (2018-11-06)
f3781e
 ==========================
f3781e
 
f3781e
+* Added support for fuse kernel feature `max_pages` which allows to increase
f3781e
+  the maximum number of pages that can be used per request. This feature was
f3781e
+  introduced in kernel 4.20. `max_pages` is set based on the value in
f3781e
+  `max_write`. By default `max_write` will be 1MiB now for kernels that support
f3781e
+  `max_pages`. If you want smaller buffers or writes you have to set
f3781e
+  `max_write` manually.
f3781e
+
f3781e
 * The `auto_unmount` mode now works correctly in combination with
f3781e
   autofs.
f3781e
 
f3781e
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
f3781e
index cf35551..d38b630 100644
f3781e
--- a/lib/fuse_i.h
f3781e
+++ b/lib/fuse_i.h
f3781e
@@ -131,3 +131,9 @@ struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *o
f3781e
 int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config);
f3781e
 int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config);
f3781e
 
f3781e
+#define FUSE_MAX_MAX_PAGES 256
f3781e
+#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
f3781e
+
f3781e
+/* room needed in buffer to accommodate header */
f3781e
+#define FUSE_BUFFER_HEADER_SIZE 0x1000
f3781e
+
f3781e
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
f3781e
index 844e797..60195e0 100644
f3781e
--- a/lib/fuse_lowlevel.c
f3781e
+++ b/lib/fuse_lowlevel.c
f3781e
@@ -1882,6 +1882,14 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
f3781e
 			se->conn.capable |= FUSE_CAP_POSIX_ACL;
f3781e
 		if (arg->flags & FUSE_HANDLE_KILLPRIV)
f3781e
 			se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
f3781e
+		if (!(arg->flags & FUSE_MAX_PAGES)) {
f3781e
+			size_t max_bufsize =
f3781e
+				FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
f3781e
+				+ FUSE_BUFFER_HEADER_SIZE;
f3781e
+			if (bufsize > max_bufsize) {
f3781e
+				bufsize = max_bufsize;
f3781e
+			}
f3781e
+		}
f3781e
 	} else {
f3781e
 		se->conn.max_readahead = 0;
f3781e
 	}
f3781e
@@ -1928,10 +1936,10 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
f3781e
 			bufsize);
f3781e
 		bufsize = FUSE_MIN_READ_BUFFER;
f3781e
 	}
f3781e
+	se->bufsize = bufsize;
f3781e
 
f3781e
-	bufsize -= 4096;
f3781e
-	if (bufsize < se->conn.max_write)
f3781e
-		se->conn.max_write = bufsize;
f3781e
+	if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE)
f3781e
+		se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
f3781e
 
f3781e
 	se->got_init = 1;
f3781e
 	if (se->op.init)
f3781e
@@ -1958,6 +1966,14 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
f3781e
 		return;
f3781e
 	}
f3781e
 
f3781e
+	if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
f3781e
+		se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
f3781e
+	}
f3781e
+	if (arg->flags & FUSE_MAX_PAGES) {
f3781e
+		outarg.flags |= FUSE_MAX_PAGES;
f3781e
+		outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
f3781e
+	}
f3781e
+
f3781e
 	/* Always enable big writes, this is superseded
f3781e
 	   by the max_write option */
f3781e
 	outarg.flags |= FUSE_BIG_WRITES;
f3781e
@@ -2779,11 +2795,6 @@ restart:
f3781e
 	return res;
f3781e
 }
f3781e
 
f3781e
-#define KERNEL_BUF_PAGES 32
f3781e
-
f3781e
-/* room needed in buffer to accommodate header */
f3781e
-#define HEADER_SIZE 0x1000
f3781e
-
f3781e
 struct fuse_session *fuse_session_new(struct fuse_args *args,
f3781e
 				      const struct fuse_lowlevel_ops *op,
f3781e
 				      size_t op_size, void *userdata)
f3781e
@@ -2844,7 +2855,8 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
f3781e
 	if (se->debug)
f3781e
 		fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
f3781e
 
f3781e
-	se->bufsize = KERNEL_BUF_PAGES * getpagesize() + HEADER_SIZE;
f3781e
+	se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
f3781e
+		FUSE_BUFFER_HEADER_SIZE;
f3781e
 
f3781e
 	list_init_req(&se->list);
f3781e
 	list_init_req(&se->interrupts);
f3781e
-- 
f3781e
2.36.1
f3781e