diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 02c00217b385..a55375ae2797 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1027,11 +1027,19 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry, return create_new_entry(fm, &args, dir, entry, S_IFLNK); } +void fuse_flush_time_update(struct inode *inode) +{ + int err = sync_inode_metadata(inode, 1); + + mapping_set_error(inode->i_mapping, err); +} + void fuse_update_ctime(struct inode *inode) { if (!IS_NOCMTIME(inode)) { inode->i_ctime = current_time(inode); mark_inode_dirty_sync(inode); + fuse_flush_time_update(inode); } } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index cad73bad9c90..d96daeaa807b 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2022,6 +2022,16 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc) */ if (!S_ISREG(inode->i_mode)) return 0; + /* + * Inode is always written before the last reference is dropped and + * hence this should not be reached from reclaim. + * + * Writing back the inode from reclaim can deadlock if the request + * processing itself needs an allocation. Allocations triggering + * reclaim while serving a request can't be prevented, because it can + * involve any number of unrelated userspace processes. + */ + WARN_ON(wbc->for_reclaim); ff = __fuse_write_file_get(fc, fi); err = fuse_flush_times(inode, ff); @@ -3559,6 +3569,8 @@ out: inode_unlock(inode); + fuse_flush_time_update(inode); + return err; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index a76019d9403f..97b44bbf5274 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1216,6 +1216,7 @@ int fuse_allow_current_process(struct fuse_conn *fc); u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id); +void fuse_flush_time_update(struct inode *inode); void fuse_update_ctime(struct inode *inode); int fuse_update_attributes(struct inode *inode, struct file *file); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 39d9d531c965..e37fba257c8b 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -125,6 +125,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) {