Cached dentries do not get revalidate, but open will result in open + getattr, but we want one 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@xxxxxxx> Cc: Miklos Szeredi <miklos@xxxxxxxxxx> Cc: Dharmendra Singh <dsingh@xxxxxxx> Cc: Horst Birthelmer <hbirthelmer@xxxxxxx> Cc: linux-fsdevel@xxxxxxxxxxxxxxx --- fs/fuse/dir.c | 52 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 701f9c51cdb1..1e5e2d46df8a 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -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: @@ -935,11 +960,10 @@ static int _fuse_atomic_open(struct inode *dir, struct dentry *entry, * return -ENOSYS for OPEN_ATOMIC after it was * aready working */ - if (unlikely(fc->has_open_atomic == 1)) { + if (unlikely(fc->has_open_atomic == 1)) pr_info("fuse server/daemon bug, atomic open " "got -ENOSYS although it was already " "succeeding before."); - } /* This should better never happen, revalidate * is missing for this entry*/ -- 2.37.2