aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.rst6
-rw-r--r--lib/fuse_i.h6
-rw-r--r--lib/fuse_lowlevel.c30
3 files changed, 33 insertions, 9 deletions
diff --git a/ChangeLog.rst b/ChangeLog.rst
index 2885775..abbd3ee 100644
--- a/ChangeLog.rst
+++ b/ChangeLog.rst
@@ -4,6 +4,12 @@ Unreleased Changes
* Added a new example (passthrough_hp). The functionality is similar
to passthrough_ll, but the implementation focuses on performance and
correctness rather than simplicity.
+* Added support for fuse kernel feature `max_pages` which allows to increase
+ the maximum number of pages that can be used per request. This feature was
+ introduced in kernel 4.20. `max_pages` is set based on the value in
+ `max_write`. By default `max_write` will be 1MiB now for kernels that support
+ `max_pages`. If you want smaller buffers or writes you have to set
+ `max_write` manually.
libfuse 3.5.0 (2019-04-16)
==========================
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index cf35551..d38b630 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -131,3 +131,9 @@ struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *o
int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config);
int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config);
+#define FUSE_MAX_MAX_PAGES 256
+#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
+
+/* room needed in buffer to accommodate header */
+#define FUSE_BUFFER_HEADER_SIZE 0x1000
+
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index c96e211..3684b8b 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -1909,6 +1909,14 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
if (arg->flags & FUSE_NO_OPENDIR_SUPPORT)
se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
+ if (!(arg->flags & FUSE_MAX_PAGES)) {
+ size_t max_bufsize =
+ FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
+ + FUSE_BUFFER_HEADER_SIZE;
+ if (bufsize > max_bufsize) {
+ bufsize = max_bufsize;
+ }
+ }
} else {
se->conn.max_readahead = 0;
}
@@ -1955,10 +1963,10 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
bufsize);
bufsize = FUSE_MIN_READ_BUFFER;
}
+ se->bufsize = bufsize;
- bufsize -= 4096;
- if (bufsize < se->conn.max_write)
- se->conn.max_write = bufsize;
+ if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE)
+ se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
se->got_init = 1;
if (se->op.init)
@@ -1985,6 +1993,14 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
return;
}
+ if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
+ se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
+ }
+ if (arg->flags & FUSE_MAX_PAGES) {
+ outarg.flags |= FUSE_MAX_PAGES;
+ outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
+ }
+
/* Always enable big writes, this is superseded
by the max_write option */
outarg.flags |= FUSE_BIG_WRITES;
@@ -2807,11 +2823,6 @@ restart:
return res;
}
-#define KERNEL_BUF_PAGES 32
-
-/* room needed in buffer to accommodate header */
-#define HEADER_SIZE 0x1000
-
struct fuse_session *fuse_session_new(struct fuse_args *args,
const struct fuse_lowlevel_ops *op,
size_t op_size, void *userdata)
@@ -2872,7 +2883,8 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
if (se->debug)
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
- se->bufsize = KERNEL_BUF_PAGES * getpagesize() + HEADER_SIZE;
+ se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
+ FUSE_BUFFER_HEADER_SIZE;
list_init_req(&se->list);
list_init_req(&se->interrupts);