We will use connection generation to detect stale inodes from the "old" fuse daemon and invalidate/revalidate them. There is no functional changes. 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/file.c | 1 + fs/fuse/fuse_i.h | 29 +++++++++++++++++++++++++++++ fs/fuse/inode.c | 2 ++ 3 files changed, 32 insertions(+) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index de37a3a06a71..1e36cd9490c6 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -79,6 +79,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_mount *fm) init_waitqueue_head(&ff->poll_wait); ff->kh = atomic64_inc_return(&fm->fc->khctr); + ff->conn_gen = READ_ONCE(fm->fc->conn_gen); return ff; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 6d3d3ca4f136..8d4276d7ab1e 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -161,6 +161,9 @@ struct fuse_inode { */ struct fuse_inode_dax *dax; #endif + + /** Fuse connection (fuse_conn) generation when inode was allocated */ + u32 conn_gen; }; /** FUSE inode state bits */ @@ -232,6 +235,9 @@ struct fuse_file { /** Has flock been performed on this file? */ bool flock:1; + + /** Fuse connection (fuse_conn) generation when file was allocated */ + u32 conn_gen; }; /** One input argument of a request */ @@ -847,6 +853,18 @@ struct fuse_conn { /* New writepages go into this bucket */ struct fuse_sync_bucket __rcu *curr_bucket; + + /** + * Connection generation. + * Used to determine if inodes/files were created with an "old" + * fuse connection and have to be invalidated. So, all requests + * related to these inodes should fail with -EIO. + * + * CHECKME: do we really need conn_gen for struct fuse_file? + * Right now it's only needed for fuse_file_put(), where we have + * no access to the inode in some cases. + */ + u32 conn_gen; }; /* @@ -910,6 +928,17 @@ static inline u64 fuse_get_attr_version(const struct fuse_conn *fc) return atomic64_read(&fc->attr_version); } +static inline bool fuse_stale_ff(const struct fuse_file *ff) +{ + return unlikely(READ_ONCE(ff->fm->fc->conn_gen) != ff->conn_gen); +} + +static inline bool fuse_stale_inode_conn(const struct inode *inode) +{ + return unlikely(READ_ONCE(get_fuse_conn(inode)->conn_gen) != + get_fuse_inode(inode)->conn_gen); +} + static inline bool fuse_stale_inode(const struct inode *inode, int generation, struct fuse_attr *attr) { diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 3de950104f15..009fe5bbb855 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -77,6 +77,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi->attr_version = 0; fi->orig_ino = 0; fi->state = 0; + fi->conn_gen = READ_ONCE(get_fuse_conn_super(sb)->conn_gen); mutex_init(&fi->mutex); spin_lock_init(&fi->lock); fi->forget = fuse_alloc_forget(); @@ -848,6 +849,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm, fc->user_ns = get_user_ns(user_ns); fc->max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ; fc->max_pages_limit = FUSE_MAX_MAX_PAGES; + fc->conn_gen = 1; INIT_LIST_HEAD(&fc->mounts); list_add(&fm->fc_entry, &fc->mounts); -- 2.34.1