@@ -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;
@@ -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);
@@ -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));
@@ -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;
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@gmail.com> --- 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(-)