Currently backing file is associated to fuse inode on the first passthrough open of the inode and detached on last passthourgh close. In preparation for attaching a backing file on lookup, allow attaching a long lived (single) reference on fuse inode backing file that will be dropped on fuse inode evict. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/fuse/file.c | 2 +- fs/fuse/fuse_i.h | 5 ++++- fs/fuse/inode.c | 6 ++++++ fs/fuse/iomode.c | 14 +++++++++++--- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index fcf20b304093..347bae2b287f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1377,7 +1377,7 @@ static void fuse_dio_lock(struct kiocb *iocb, struct iov_iter *from, * have raced, so check it again. */ if (fuse_io_past_eof(iocb, from) || - fuse_inode_uncached_io_start(fi, NULL) != 0) { + fuse_inode_uncached_io_start(fi, NULL, false) != 0) { inode_unlock_shared(inode); inode_lock(inode); *exclusive = true; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index f23919610313..2f340fd05e8a 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -209,6 +209,8 @@ enum { FUSE_I_BTIME, /* Wants or already has page cache IO */ FUSE_I_CACHE_IO_MODE, + /* Long lived backing file */ + FUSE_I_BACKING, }; struct fuse_conn; @@ -1396,7 +1398,8 @@ int fuse_fileattr_set(struct mnt_idmap *idmap, /* iomode.c */ int fuse_file_cached_io_open(struct inode *inode, struct fuse_file *ff); int fuse_inode_uncached_io_start(struct fuse_inode *fi, - struct fuse_backing *fb); + struct fuse_backing *fb, + bool keep_fb); void fuse_inode_uncached_io_end(struct fuse_inode *fi); int fuse_file_io_open(struct file *file, struct inode *inode); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 99e44ea7d875..989a84f6a825 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -175,6 +175,12 @@ static void fuse_evict_inode(struct inode *inode) } } if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) { + /* fuse inode may have a long lived reference to backing file */ + if (fuse_inode_backing(fi)) { + WARN_ON(!test_bit(FUSE_I_BACKING, &fi->state)); + fuse_inode_uncached_io_end(fi); + } + WARN_ON(fi->iocachectr != 0); WARN_ON(!list_empty(&fi->write_files)); WARN_ON(!list_empty(&fi->queued_writes)); diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c index f9e30c4540af..b1ff43668800 100644 --- a/fs/fuse/iomode.c +++ b/fs/fuse/iomode.c @@ -80,8 +80,14 @@ static void fuse_file_cached_io_release(struct fuse_file *ff, spin_unlock(&fi->lock); } -/* Start strictly uncached io mode where cache access is not allowed */ -int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb) +/* + * Start strictly uncached io mode where cache access is not allowed. + * + * With @keep_fb true, the backing file reference is expected to be dropped + * on inode evict. + */ +int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb, + bool keep_fb) { struct fuse_backing *oldfb; int err = 0; @@ -103,6 +109,8 @@ int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb) if (fb && !oldfb) { oldfb = fuse_inode_backing_set(fi, fb); WARN_ON_ONCE(oldfb != NULL); + if (keep_fb) + set_bit(FUSE_I_BACKING, &fi->state); } else { fuse_backing_put(fb); } @@ -119,7 +127,7 @@ static int fuse_file_uncached_io_open(struct inode *inode, struct fuse_inode *fi = get_fuse_inode(inode); int err; - err = fuse_inode_uncached_io_start(fi, fb); + err = fuse_inode_uncached_io_start(fi, fb, false); if (err) return err; -- 2.34.1