[Thanks to Andrew for CCing me on patch commit]
On Sun 14-12-25 19:00:43, Joanne Koong wrote:
Skip waiting on writeback for inodes that belong to mappings that do not have data integrity guarantees (denoted by the AS_NO_DATA_INTEGRITY mapping flag).
This restores fuse back to prior behavior where syncs are no-ops. This is needed because otherwise, if a system is running a faulty fuse server that does not reply to issued write requests, this will cause wait_sb_inodes() to wait forever.
Fixes: 0c58a97f919c ("fuse: remove tmp folio for writebacks and internal rb tree") Reported-by: Athul Krishna athul.krishna.kr@protonmail.com Reported-by: J. Neuschäfer j.neuschaefer@gmx.net Cc: stable@vger.kernel.org Signed-off-by: Joanne Koong joannelkoong@gmail.com
OK, but the difference 0c58a97f919c introduced goes much further than just wait_sb_inodes(). Before 0c58a97f919c also filemap_fdatawait() (and all the other variants waiting for folio_writeback() to clear) returned immediately because folio writeback was done as soon as we've copied the content into the temporary page. Now they will block waiting for the server to finish the IO. So e.g. fsync() will block waiting for the server in file_write_and_wait_range() now, instead of blocking in fuse_fsync_common() -> fuse_simple_request(). Similarly e.g. truncate(2) will now block waiting for the server so that folio_writeback can be cleared.
So I understand your patch fixes the regression with suspend blocking but I don't have a high confidence we are not just starting a whack-a-mole game catching all the places that previously hiddenly depended on folio_writeback getting cleared without any involvement of untrusted fuse server and now this changed. So do we have some higher-level idea what is / is not guaranteed with stuck fuse server?
Honza
fs/fs-writeback.c | 3 ++- fs/fuse/file.c | 4 +++- include/linux/pagemap.h | 11 +++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 6800886c4d10..ab2e279ed3c2 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -2751,7 +2751,8 @@ static void wait_sb_inodes(struct super_block *sb) * do not have the mapping lock. Skip it here, wb completion * will remove it. */
if (!mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK))
if (!mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK) ||mapping_no_data_integrity(mapping)) continue;spin_unlock_irq(&sb->s_inode_wblist_lock); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 01bc894e9c2b..3b2a171e652f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -3200,8 +3200,10 @@ void fuse_init_file_inode(struct inode *inode, unsigned int flags) inode->i_fop = &fuse_file_operations; inode->i_data.a_ops = &fuse_file_aops;
- if (fc->writeback_cache)
- if (fc->writeback_cache) { mapping_set_writeback_may_deadlock_on_reclaim(&inode->i_data);
mapping_set_no_data_integrity(&inode->i_data);- }
INIT_LIST_HEAD(&fi->write_files); INIT_LIST_HEAD(&fi->queued_writes); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 31a848485ad9..ec442af3f886 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -210,6 +210,7 @@ enum mapping_flags { AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, AS_KERNEL_FILE = 10, /* mapping for a fake kernel file that shouldn't account usage to user cgroups */
- AS_NO_DATA_INTEGRITY = 11, /* no data integrity guarantees */ /* Bits 16-25 are used for FOLIO_ORDER */ AS_FOLIO_ORDER_BITS = 5, AS_FOLIO_ORDER_MIN = 16,
@@ -345,6 +346,16 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(const struct addres return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); } +static inline void mapping_set_no_data_integrity(struct address_space *mapping) +{
- set_bit(AS_NO_DATA_INTEGRITY, &mapping->flags);
+}
+static inline bool mapping_no_data_integrity(const struct address_space *mapping) +{
- return test_bit(AS_NO_DATA_INTEGRITY, &mapping->flags);
+}
static inline gfp_t mapping_gfp_mask(const struct address_space *mapping) { return mapping->gfp_mask; -- 2.47.3