From c66e7f4e71a10e0a06d903d11acad8cc6b99c16a Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 7 Feb 2013 02:52:41 +0000 Subject: [PATCH] libfuse: allow disabling adaptive readdirplus This switches the -o no_readdirplus option to a tristate string: -o readdirplus=(yes|no|auto) Telling the kernel to always use readdirplus is beneficial to filesystems (e.g. GlusterFS) where the cost to perform readdir and readdirplus are identical. The default remains "auto" (if supported). --- include/fuse_common.h | 1 + include/fuse_kernel.h | 3 +++ lib/fuse_i.h | 1 + lib/fuse_lowlevel.c | 20 ++++++++++++++++---- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/include/fuse_common.h b/include/fuse_common.h index cb2d8cf..78d3ce4 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -118,6 +118,7 @@ struct fuse_file_info { #define FUSE_CAP_IOCTL_DIR (1 << 11) #define FUSE_CAP_AUTO_INVAL_DATA (1 << 12) #define FUSE_CAP_READDIRPLUS (1 << 13) +#define FUSE_CAP_READDIRPLUS_AUTO (1 << 14) /** * Ioctl flags diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h index baee03e..4c43b44 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -218,6 +218,8 @@ struct fuse_file_lock { * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages + * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one) + * FUSE_READDIRPLUS_AUTO: adaptive readdirplus */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) @@ -233,6 +235,7 @@ struct fuse_file_lock { #define FUSE_HAS_IOCTL_DIR (1 << 11) #define FUSE_AUTO_INVAL_DATA (1 << 12) #define FUSE_DO_READDIRPLUS (1 << 13) +#define FUSE_READDIRPLUS_AUTO (1 << 14) /** * CUSE INIT request/reply flags diff --git a/lib/fuse_i.h b/lib/fuse_i.h index 02e7af1..3c46d34 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -74,6 +74,7 @@ struct fuse_ll { int auto_inval_data; int no_auto_inval_data; int no_readdirplus; + int no_readdirplus_auto; struct fuse_lowlevel_ops op; int got_init; struct cuse_data *cuse_data; diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 2ac9aab..4f9cff8 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -1843,6 +1843,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) f->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA; if (arg->flags & FUSE_DO_READDIRPLUS) f->conn.capable |= FUSE_CAP_READDIRPLUS; + if (arg->flags & FUSE_READDIRPLUS_AUTO) + f->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO; } else { f->conn.async_read = 0; f->conn.max_readahead = 0; @@ -1875,8 +1877,11 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) f->conn.want |= FUSE_CAP_BIG_WRITES; if (f->auto_inval_data) f->conn.want |= FUSE_CAP_AUTO_INVAL_DATA; - if (f->op.readdirplus && !f->no_readdirplus) + if (f->op.readdirplus && !f->no_readdirplus) { f->conn.want |= FUSE_CAP_READDIRPLUS; + if (!f->no_readdirplus_auto) + f->conn.want |= FUSE_CAP_READDIRPLUS_AUTO; + } if (bufsize < FUSE_MIN_READ_BUFFER) { fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", @@ -1902,7 +1907,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) f->conn.want &= ~FUSE_CAP_AUTO_INVAL_DATA; if (f->no_readdirplus) f->conn.want &= ~FUSE_CAP_READDIRPLUS; - + if (f->no_readdirplus_auto) + f->conn.want &= ~FUSE_CAP_READDIRPLUS_AUTO; if (f->conn.async_read || (f->conn.want & FUSE_CAP_ASYNC_READ)) outarg.flags |= FUSE_ASYNC_READ; if (f->conn.want & FUSE_CAP_POSIX_LOCKS) @@ -1921,6 +1927,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) outarg.flags |= FUSE_AUTO_INVAL_DATA; if (f->conn.want & FUSE_CAP_READDIRPLUS) outarg.flags |= FUSE_DO_READDIRPLUS; + if (f->conn.want & FUSE_CAP_READDIRPLUS_AUTO) + outarg.flags |= FUSE_READDIRPLUS_AUTO; outarg.max_readahead = f->conn.max_readahead; outarg.max_write = f->conn.max_write; if (f->conn.proto_minor >= 13) { @@ -2546,7 +2554,11 @@ static const struct fuse_opt fuse_ll_opts[] = { { "no_splice_read", offsetof(struct fuse_ll, no_splice_read), 1}, { "auto_inval_data", offsetof(struct fuse_ll, auto_inval_data), 1}, { "no_auto_inval_data", offsetof(struct fuse_ll, no_auto_inval_data), 1}, - { "no_readdirplus", offsetof(struct fuse_ll, no_readdirplus), 1}, + { "readdirplus=no", offsetof(struct fuse_ll, no_readdirplus), 1}, + { "readdirplus=yes", offsetof(struct fuse_ll, no_readdirplus), 0}, + { "readdirplus=yes", offsetof(struct fuse_ll, no_readdirplus_auto), 1}, + { "readdirplus=auto", offsetof(struct fuse_ll, no_readdirplus), 0}, + { "readdirplus=auto", offsetof(struct fuse_ll, no_readdirplus_auto), 0}, FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("-h", KEY_HELP), FUSE_OPT_KEY("--help", KEY_HELP), @@ -2579,7 +2591,7 @@ static void fuse_ll_help(void) " -o [no_]splice_move move data while splicing to the fuse device\n" " -o [no_]splice_read use splice to read from the fuse device\n" " -o [no_]auto_inval_data use automatic kernel cache invalidation logic\n" -" -o [no_]readdirplus use readdirplus if possible.\n" +" -o readdirplus=S control readdirplus use (yes|no|auto)\n" ); } -- 2.30.2