libfuse: allow disabling adaptive readdirplus
authorEric Wong <normalperson@yhbt.net>
Thu, 7 Feb 2013 02:52:41 +0000 (02:52 +0000)
committerMiklos Szeredi <mszeredi@suse.cz>
Thu, 7 Feb 2013 13:59:28 +0000 (14:59 +0100)
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
include/fuse_kernel.h
lib/fuse_i.h
lib/fuse_lowlevel.c

index cb2d8cf852ceaa9d6d88eeb2bba5200222ef98df..78d3ce4feaa898d2f31287658bfa3bc865ac3fde 100644 (file)
@@ -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
index baee03e9043876139aef109c46c56a9b8af772e2..4c43b44487922301a3c7949ee6c07020e50e248e 100644 (file)
@@ -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
index 02e7af1d36f8911ea8fe32e6b4579a35ea428232..3c46d343f6403bb08e9a936e762e6a090c3f38d5 100644 (file)
@@ -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;
index 2ac9aab65034e5b76416417b2c4c97f37ae20a9b..4f9cff88b8fd4502a609478dcc4e1f28e283db52 100644 (file)
@@ -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"
 );
 }