aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/inode.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2021-10-22 17:03:01 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2021-10-22 17:03:01 +0200
commit5c791fe1e2a4f401f819065ea4fc0450849f1818 (patch)
tree152b7cd2888395c394e1ed6eb82e94b238421574 /fs/fuse/inode.c
parentfuse: clean up error exits in fuse_fill_super() (diff)
downloadlinux-dev-5c791fe1e2a4f401f819065ea4fc0450849f1818.tar.xz
linux-dev-5c791fe1e2a4f401f819065ea4fc0450849f1818.zip
fuse: make sure reclaim doesn't write the inode
In writeback cache mode mtime/ctime updates are cached, and flushed to the server using the ->write_inode() callback. Closing the file will result in a dirty inode being immediately written, but in other cases the inode can remain dirty after all references are dropped. This result in the inode being written back from reclaim, which can deadlock on a regular allocation while the request is being served. The usual mechanisms (GFP_NOFS/PF_MEMALLOC*) don't work for FUSE, because serving a request involves unrelated userspace process(es). Instead do the same as for dirty pages: make sure the inode is written before the last reference is gone. - fallocate(2)/copy_file_range(2): these call file_update_time() or file_modified(), so flush the inode before returning from the call - unlink(2), link(2) and rename(2): these call fuse_update_ctime(), so flush the ctime directly from this helper Reported-by: chenguanyou <chenguanyou@xiaomi.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to '')
-rw-r--r--fs/fuse/inode.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 12d49a1914e8..2f999d38c9b4 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -118,6 +118,9 @@ static void fuse_evict_inode(struct inode *inode)
{
struct fuse_inode *fi = get_fuse_inode(inode);
+ /* Will write inode on close/munmap and in all other dirtiers */
+ WARN_ON(inode->i_state & I_DIRTY_INODE);
+
truncate_inode_pages_final(&inode->i_data);
clear_inode(inode);
if (inode->i_sb->s_flags & SB_ACTIVE) {