aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Nikolaus Rath <Nikolaus@rath.org>2016-10-10 15:52:15 -0700
committerGravatar Nikolaus Rath <Nikolaus@rath.org>2016-10-13 10:35:12 -0700
commitdc436101370e0ab2ea4d3a2a3454711ad7051ae8 (patch)
treece2f8849c607282ad3b5ea0c37fa2a4a45712c50
parent054c03943a6dc6a84ec7e52adcc661988b954871 (diff)
do_init(): treat command line options consistently
Previously, some command line options would change the FUSE defaults but leave the final value to the file systems `init` handler while others would override any changes made by `init`. Now, command line options do both: they modify the default, *and* take precedence.
-rw-r--r--ChangeLog.rst6
-rw-r--r--include/fuse_common.h7
-rw-r--r--include/fuse_lowlevel.h9
-rw-r--r--lib/fuse_lowlevel.c100
4 files changed, 72 insertions, 50 deletions
diff --git a/ChangeLog.rst b/ChangeLog.rst
index dc243f2..4f355ce 100644
--- a/ChangeLog.rst
+++ b/ChangeLog.rst
@@ -1,6 +1,12 @@
Unreleased Changes
==================
+* `fuse_session_new` now treats low-level options more consistently:
+ First, options are used to modify FUSE defaults. Second, the file
+ system may inspect and/or adjust the settings in its `init`
+ handler. Third, command line arguments take precedence over any
+ modifications made by the `init` handler.
+
* Removed the `async_read` field from `struct fuse_conn_info`. To
determine if the kernel supports asynchronous reads, file systems
should check the `FUSE_CAP_ASYNC_READ` bit of the `capable`
diff --git a/include/fuse_common.h b/include/fuse_common.h
index 4a0e94b..55f0de2 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -167,12 +167,15 @@ struct fuse_conn_info {
unsigned max_readahead;
/**
- * Capability flags, that the kernel supports
+ * Capability flags that the kernel supports (read-only)
*/
unsigned capable;
/**
- * Capability flags, that the filesystem wants to enable
+ * Capability flags that the filesystem wants to enable.
+ *
+ * libfuse attempts to initialize this field with
+ * reasonable default values before calling the init() handler.
*/
unsigned want;
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index 63c59c9..bad1d45 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -165,7 +165,14 @@ struct fuse_lowlevel_ops {
/**
* Initialize filesystem
*
- * Called before any other filesystem method
+ * This function is called when libfuse establishes
+ * communication with the FUSE kernel module. The file system
+ * should use this module to inspect and/or modify the
+ * connection parameters provided in the `conn` structure.
+ *
+ * Note that some parameters may be overwritten by options
+ * passed to fuse_session_new() which take precedence over the
+ * values set in this handler.
*
* There's no reply to this function
*
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 299d4a8..3b30b21 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -1809,6 +1809,39 @@ static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
fuse_reply_err(req, ENOSYS);
}
+static void apply_want_options(struct fuse_session *opts,
+ struct fuse_conn_info *conn)
+{
+#define LL_ENABLE(cond,cap) \
+ if (cond) conn->want |= (cap)
+#define LL_DISABLE(cond,cap) \
+ if (cond) conn->want &= ~(cap)
+
+ LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
+ LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
+
+ LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
+ LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
+
+ LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
+ LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
+
+ LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
+ LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
+
+ LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
+ LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
+
+ LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
+ LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
+
+ LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
+ LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
+
+ LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
+ LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
+}
+
static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
@@ -1851,11 +1884,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
if (arg->minor >= 6) {
if (arg->max_readahead < f->conn.max_readahead)
f->conn.max_readahead = arg->max_readahead;
- if (arg->flags & FUSE_ASYNC_READ) {
+ if (arg->flags & FUSE_ASYNC_READ)
f->conn.capable |= FUSE_CAP_ASYNC_READ;
- /* Enable by default */
- f->conn.want |= FUSE_CAP_ASYNC_READ;
- }
if (arg->flags & FUSE_POSIX_LOCKS)
f->conn.capable |= FUSE_CAP_POSIX_LOCKS;
if (arg->flags & FUSE_ATOMIC_O_TRUNC)
@@ -1886,36 +1916,23 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
#ifdef HAVE_SPLICE
#ifdef HAVE_VMSPLICE
f->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
- if (f->splice_write)
- f->conn.want |= FUSE_CAP_SPLICE_WRITE;
- if (f->splice_move)
- f->conn.want |= FUSE_CAP_SPLICE_MOVE;
#endif
f->conn.capable |= FUSE_CAP_SPLICE_READ;
- if (f->splice_read)
- f->conn.want |= FUSE_CAP_SPLICE_READ;
#endif
}
if (f->conn.proto_minor >= 18)
f->conn.capable |= FUSE_CAP_IOCTL_DIR;
- if (f->atomic_o_trunc)
- f->conn.want |= FUSE_CAP_ATOMIC_O_TRUNC;
- if (f->op.getlk && f->op.setlk && !f->no_remote_posix_lock)
- f->conn.want |= FUSE_CAP_POSIX_LOCKS;
- if (f->op.flock && !f->no_remote_flock)
- f->conn.want |= FUSE_CAP_FLOCK_LOCKS;
- if (f->auto_inval_data)
- f->conn.want |= FUSE_CAP_AUTO_INVAL_DATA;
- 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 (f->async_dio)
- f->conn.want |= FUSE_CAP_ASYNC_DIO;
- if (f->writeback_cache)
- f->conn.want |= FUSE_CAP_WRITEBACK_CACHE;
+ /* Default settings (where non-zero) */
+#define LL_SET_DEFAULT(cond, cap) \
+ if ((cond) && (f->conn.capable & (cap))) \
+ f->conn.want |= (cap)
+ LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
+ LL_SET_DEFAULT(f->op.getlk && f->op.setlk,
+ FUSE_CAP_POSIX_LOCKS);
+ LL_SET_DEFAULT(f->op.flock, FUSE_CAP_FLOCK_LOCKS);
+ LL_SET_DEFAULT(f->op.readdirplus, FUSE_CAP_READDIRPLUS);
+ LL_SET_DEFAULT(f->op.readdirplus, FUSE_CAP_READDIRPLUS_AUTO);
if (bufsize < FUSE_MIN_READ_BUFFER) {
fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
@@ -1928,29 +1945,18 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
f->conn.max_write = bufsize;
f->got_init = 1;
+
+ /* Apply command-line options (so that init() handler has
+ an idea about user preferences */
+ apply_want_options(f, &f->conn);
+
+ /* Allow file-system to overwrite defaults */
if (f->op.init)
f->op.init(f->userdata, &f->conn);
- if (f->no_splice_read)
- f->conn.want &= ~FUSE_CAP_SPLICE_READ;
- if (f->no_splice_write)
- f->conn.want &= ~FUSE_CAP_SPLICE_WRITE;
- if (f->no_splice_move)
- f->conn.want &= ~FUSE_CAP_SPLICE_MOVE;
- if (f->no_auto_inval_data)
- 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->no_async_dio)
- f->conn.want &= ~FUSE_CAP_ASYNC_DIO;
- if (f->no_writeback_cache)
- f->conn.want &= ~FUSE_CAP_WRITEBACK_CACHE;
- if (f->async_read)
- f->conn.want |= FUSE_CAP_ASYNC_READ;
- if (f->sync_read)
- f->conn.want &= ~FUSE_CAP_ASYNC_READ;
+ /* Now explicitly overwrite file-system's decision
+ with command-line options */
+ apply_want_options(f, &f->conn);
/* Always enable big writes, this is superseded
by the max_write option */