diff options
-rw-r--r-- | ChangeLog.rst | 6 | ||||
-rw-r--r-- | lib/fuse_i.h | 6 | ||||
-rw-r--r-- | lib/fuse_lowlevel.c | 30 |
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); |