lkml.org 
[lkml]   [2023]   [Apr]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC PATCH v2 6/9] fuse: take fuse connection generation into account
    Date
    - modify dentry revalidation algorithm to check inode/connection
    generations. If them are not equal then perform revalidation.

    remark: during forced dentry revalidation we are sending FUSE_LOOKUP
    request to the userspace daemon and if it return the same inode after
    lookup then we can "upgrade" inode connection generation without
    invalidating it.

    - don't send FUSE_FSYNC, FUSE_RELEASE, etc requests to the userspace
    daemon about stale inodes (this can confuse libfuse)

    Cc: Miklos Szeredi <mszeredi@redhat.com>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Cc: Amir Goldstein <amir73il@gmail.com>
    Cc: Stéphane Graber <stgraber@ubuntu.com>
    Cc: Seth Forshee <sforshee@kernel.org>
    Cc: Christian Brauner <brauner@kernel.org>
    Cc: Andrei Vagin <avagin@gmail.com>
    Cc: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
    Cc: Bernd Schubert <bschubert@ddn.com>
    Cc: linux-fsdevel@vger.kernel.org
    Cc: linux-kernel@vger.kernel.org
    Cc: criu@openvz.org
    Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
    ---
    fs/fuse/dir.c | 4 +++-
    fs/fuse/file.c | 13 ++++++++++---
    fs/fuse/fuse_i.h | 3 ++-
    fs/fuse/inode.c | 2 +-
    4 files changed, 16 insertions(+), 6 deletions(-)

    diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
    index bfbe59e8fce2..d0fdf7289d56 100644
    --- a/fs/fuse/dir.c
    +++ b/fs/fuse/dir.c
    @@ -213,7 +213,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
    inode = d_inode_rcu(entry);
    if (inode && fuse_is_bad(inode))
    goto invalid;
    - else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
    + else if ((inode && fuse_stale_inode_conn(inode)) ||
    + time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
    (flags & (LOOKUP_EXCL | LOOKUP_REVAL | LOOKUP_RENAME_TARGET))) {
    struct fuse_entry_out outarg;
    FUSE_ARGS(args);
    @@ -255,6 +256,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
    }
    spin_lock(&fi->lock);
    fi->nlookup++;
    + fi->conn_gen = READ_ONCE(get_fuse_conn(inode)->conn_gen);
    spin_unlock(&fi->lock);
    }
    kfree(forget);
    diff --git a/fs/fuse/file.c b/fs/fuse/file.c
    index 742f90b4e638..b977d087b925 100644
    --- a/fs/fuse/file.c
    +++ b/fs/fuse/file.c
    @@ -111,8 +111,14 @@ static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir)
    if (refcount_dec_and_test(&ff->count)) {
    struct fuse_args *args = &ff->release_args->args;

    - if (isdir ? ff->fm->fc->flags.no_opendir : ff->fm->fc->flags.no_open) {
    - /* Do nothing when client does not implement 'open' */
    + if (fuse_stale_ff(ff) ||
    + (isdir ? ff->fm->fc->flags.no_opendir : ff->fm->fc->flags.no_open)) {
    + /*
    + * Do nothing when client does not implement 'open' OR
    + * file descriptor was opened in the previous connection generation,
    + * so, current daemon likely not aware of this FD, let's just skip
    + * FUSE_RELEASE(DIR) request.
    + */
    fuse_release_end(ff->fm, args, 0);
    } else if (sync) {
    fuse_simple_request(ff->fm, args);
    @@ -598,9 +604,10 @@ static int fuse_fsync(struct file *file, loff_t start, loff_t end,
    {
    struct inode *inode = file->f_mapping->host;
    struct fuse_conn *fc = get_fuse_conn(inode);
    + struct fuse_file *ff = file->private_data;
    int err;

    - if (fuse_is_bad(inode))
    + if (fuse_stale_ff(ff) || fuse_is_bad(inode))
    return -EIO;

    inode_lock(inode);
    diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
    index 943d5011dfa0..90c5b3459864 100644
    --- a/fs/fuse/fuse_i.h
    +++ b/fs/fuse/fuse_i.h
    @@ -957,7 +957,8 @@ static inline bool fuse_stale_inode(const struct inode *inode, int generation,
    struct fuse_attr *attr)
    {
    return inode->i_generation != generation ||
    - inode_wrong_type(inode, attr->mode);
    + inode_wrong_type(inode, attr->mode) ||
    + fuse_stale_inode_conn(inode);
    }

    static inline void fuse_make_bad(struct inode *inode)
    diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
    index 389bea6e4a69..26a4149f6db7 100644
    --- a/fs/fuse/inode.c
    +++ b/fs/fuse/inode.c
    @@ -124,7 +124,7 @@ static void fuse_evict_inode(struct inode *inode)
    fuse_dax_inode_cleanup(inode);
    if (fi->nlookup) {
    fuse_queue_forget(fc, fi->forget, fi->nodeid,
    - fi->nlookup, false);
    + fi->nlookup, fuse_stale_inode_conn(inode));
    fi->forget = NULL;
    }
    }
    --
    2.34.1
    \
     
     \ /
      Last update: 2023-04-03 16:47    [W:5.344 / U:0.096 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site