We don't want to send FUSE_FORGET request to the new fuse daemon if inode was lookuped by the old fuse daemon because it can confuse and break userspace (libfuse). For now, just add a new argument to fuse_queue_forget and handle it. Adjust all callers to match the old behaviour. Cc: Miklos Szeredi <mszeredi@xxxxxxxxxx> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Amir Goldstein <amir73il@xxxxxxxxx> Cc: Stéphane Graber <stgraber@xxxxxxxxxx> Cc: Seth Forshee <sforshee@xxxxxxxxxx> Cc: Christian Brauner <brauner@xxxxxxxxxx> Cc: Andrei Vagin <avagin@xxxxxxxxx> Cc: Pavel Tikhomirov <ptikhomirov@xxxxxxxxxxxxx> Cc: Bernd Schubert <bschubert@xxxxxxx> Cc: linux-fsdevel@xxxxxxxxxxxxxxx Cc: linux-kernel@xxxxxxxxxxxxxxx Cc: criu@xxxxxxxxxx Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@xxxxxxxxxxxxx> --- fs/fuse/dev.c | 4 ++-- fs/fuse/dir.c | 8 ++++---- fs/fuse/fuse_i.h | 2 +- fs/fuse/inode.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index eb4f88e3dc97..2e7cd60b685e 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -234,7 +234,7 @@ __releases(fiq->lock) } void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, - u64 nodeid, u64 nlookup) + u64 nodeid, u64 nlookup, bool stale_inode_conn) { struct fuse_iqueue *fiq = &fc->iq; @@ -242,7 +242,7 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, forget->forget_one.nlookup = nlookup; spin_lock(&fiq->lock); - if (fiq->connected) { + if (fiq->connected && likely(!stale_inode_conn)) { fiq->forget_list_tail->next = forget; fiq->forget_list_tail = forget; fiq->ops->wake_forget_and_unlock(fiq); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 5a4a7155cf1c..7e308a655191 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -250,7 +250,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) if (outarg.nodeid != get_node_id(inode) || (bool) IS_AUTOMOUNT(inode) != (bool) (outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) { fuse_queue_forget(fm->fc, forget, - outarg.nodeid, 1); + outarg.nodeid, 1, false); goto invalid; } spin_lock(&fi->lock); @@ -403,7 +403,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name attr_version); err = -ENOMEM; if (!*inode) { - fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1); + fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1, false); goto out; } err = 0; @@ -690,7 +690,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, if (!inode) { flags &= ~(O_CREAT | O_EXCL | O_TRUNC); fuse_sync_release(NULL, ff, flags); - fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); + fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1, false); err = -ENOMEM; goto out_err; } @@ -815,7 +815,7 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args, inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr, entry_attr_timeout(&outarg), 0); if (!inode) { - fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); + fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1, false); return -ENOMEM; } kfree(forget); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 8d4276d7ab1e..be5d5d3fe6f5 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1008,7 +1008,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name * Send FORGET command */ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, - u64 nodeid, u64 nlookup); + u64 nodeid, u64 nlookup, bool stale_inode_conn); struct fuse_forget_link *fuse_alloc_forget(void); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 009fe5bbb855..e5ad5d4c215a 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); + fi->nlookup, false); fi->forget = NULL; } } -- 2.34.1