@@ -193,6 +193,22 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
args->out_args[0].value = outarg;
}
+/*
+ * If open atomic is supported by FUSE then use this opportunity
+ * to avoid this lookup and combine lookup + open into a single call.
+ */
+static int fuse_dentry_do_atomic_revalidate(struct dentry *entry,
+ unsigned int flags,
+ struct fuse_conn *fc)
+{
+ int ret = 0;
+
+ if (flags & LOOKUP_OPEN && fc->has_open_atomic)
+ ret = D_REVALIDATE_ATOMIC;
+
+ return ret;
+}
+
/*
* Check whether the dentry is still valid
*
@@ -230,19 +246,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
fm = get_fuse_mount(inode);
- /* If open atomic is supported by FUSE then use this opportunity
- * to avoid this lookup and combine lookup + open into a single call.
- *
- * Note: Fuse detects open atomic implementation automatically.
- * Therefore first few call would go into open atomic code path
- * , detects that open atomic is implemented or not by setting
- * fc->no_open_atomic. In case open atomic is not implemented,
- * calls fall back to non-atomic open.
- */
- if (fm->fc->has_open_atomic && flags & LOOKUP_OPEN) {
- ret = D_REVALIDATE_ATOMIC;
+ ret = fuse_dentry_do_atomic_revalidate(entry, flags, fm->fc);
+ if (ret)
goto out;
- }
+
forget = fuse_alloc_forget();
ret = -ENOMEM;
if (!forget)
@@ -285,6 +292,16 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
} else if (inode) {
fi = get_fuse_inode(inode);
if (flags & LOOKUP_RCU) {
+ fm = get_fuse_mount(inode);
+ if (fm->fc->has_open_atomic) {
+ /* Atomic open is preferred, as it does entry
+ * revalidate and attribute refresh, but
+ * DCACHE_ATOMIC_OPEN cannot be set in RCU mode
+ */
+ if (flags & LOOKUP_OPEN)
+ return -ECHILD;
+ }
+
if (test_bit(FUSE_I_INIT_RDPLUS, &fi->state))
return -ECHILD;
} else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) {
@@ -292,6 +309,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
fuse_advise_use_readdirplus(d_inode(parent));
dput(parent);
}
+
+ /* revalidate is skipped, but we still want atomic open to
+ * update attributes during open
+ */
+ fm = get_fuse_mount(inode);
+ ret = fuse_dentry_do_atomic_revalidate(entry, flags, fm->fc);
+ if (ret)
+ goto out;
}
ret = D_REVALIDATE_VALID;
out:
Cached dentries do not get revalidate, but open would still result in open + getattr, instead of one atomic_open call only. libfuse logs (passthrough_hp): Unpatched: ---------- unique: 22, opcode: OPEN (14), nodeid: 140698229673544, insize: 48, pid: 3434 unique: 22, success, outsize: 32 unique: 24, opcode: GETATTR (3), nodeid: 140698229673544, insize: 56, pid: 3434 unique: 24, success, outsize: 120 unique: 26, opcode: FLUSH (25), nodeid: 140698229673544, insize: 64, pid: 3434 unique: 26, success, outsize: 16 unique: 28, opcode: RELEASE (18), nodeid: 140698229673544, insize: 64, pid: 0 unique: 28, success, outsize: 16 Patched: ---------- unique: 20, opcode: OPEN_ATOMIC (52), nodeid: 1, insize: 63, pid: 3397 unique: 20, success, outsize: 160 unique: 22, opcode: FLUSH (25), nodeid: 140024188243528, insize: 64, pid: 3397 unique: 22, success, outsize: 16 unique: 24, opcode: RELEASE (18), nodeid: 140024188243528, insize: 64, pid: 0 unique: 24, success, outsize: 16 Signed-off-by: Bernd Schubert <bschubert@ddn.com> Cc: Miklos Szeredi <miklos@szeredi.hu> Cc: Dharmendra Singh <dsingh@ddn.com> Cc: Horst Birthelmer <hbirthelmer@ddn.com> Cc: linux-fsdevel@vger.kernel.org --- fs/fuse/dir.c | 49 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-)