]> git.itanic.dy.fi Git - linux-stable/commitdiff
filemap: add a per-mapping stable writes flag
authorChristoph Hellwig <hch@lst.de>
Wed, 25 Oct 2023 14:10:17 +0000 (16:10 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 20 Nov 2023 14:05:18 +0000 (15:05 +0100)
folio_wait_stable waits for writeback to finish before modifying the
contents of a folio again, e.g. to support check summing of the data
in the block integrity code.

Currently this behavior is controlled by the SB_I_STABLE_WRITES flag
on the super_block, which means it is uniform for the entire file system.
This is wrong for the block device pseudofs which is shared by all
block devices, or file systems that can use multiple devices like XFS
witht the RT subvolume or btrfs (although btrfs currently reimplements
folio_wait_stable anyway).

Add a per-address_space AS_STABLE_WRITES flag to control the behavior
in a more fine grained way.  The existing SB_I_STABLE_WRITES is kept
to initialize AS_STABLE_WRITES to the existing default which covers
most cases.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20231025141020.192413-2-hch@lst.de
Tested-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/inode.c
include/linux/pagemap.h
mm/page-writeback.c

index edcd8a61975f34c7a4cf467589848870430b3b8a..f238d987dec901150ac759d51a7996dc208bd1f8 100644 (file)
@@ -215,6 +215,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        lockdep_set_class_and_name(&mapping->invalidate_lock,
                                   &sb->s_type->invalidate_lock_key,
                                   "mapping.invalidate_lock");
+       if (sb->s_iflags & SB_I_STABLE_WRITES)
+               mapping_set_stable_writes(mapping);
        inode->i_private = NULL;
        inode->i_mapping = mapping;
        INIT_HLIST_HEAD(&inode->i_dentry);      /* buggered by rcu freeing */
index bcc1ea44b4e8541aea3cfe5fc601d2a9bf8c4295..06142ff7f9ce0ef0c600c3aa24f68b1bd5450bdb 100644 (file)
@@ -204,6 +204,8 @@ enum mapping_flags {
        AS_NO_WRITEBACK_TAGS = 5,
        AS_LARGE_FOLIO_SUPPORT = 6,
        AS_RELEASE_ALWAYS,      /* Call ->release_folio(), even if no private data */
+       AS_STABLE_WRITES,       /* must wait for writeback before modifying
+                                  folio contents */
 };
 
 /**
@@ -289,6 +291,21 @@ static inline void mapping_clear_release_always(struct address_space *mapping)
        clear_bit(AS_RELEASE_ALWAYS, &mapping->flags);
 }
 
+static inline bool mapping_stable_writes(const struct address_space *mapping)
+{
+       return test_bit(AS_STABLE_WRITES, &mapping->flags);
+}
+
+static inline void mapping_set_stable_writes(struct address_space *mapping)
+{
+       set_bit(AS_STABLE_WRITES, &mapping->flags);
+}
+
+static inline void mapping_clear_stable_writes(struct address_space *mapping)
+{
+       clear_bit(AS_STABLE_WRITES, &mapping->flags);
+}
+
 static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
 {
        return mapping->gfp_mask;
index 46f2f5d3d183b586e9936a92ed08ba08f6bf9755..ee2fd6a6af40728b3990773b464f362222be0621 100644 (file)
@@ -3107,7 +3107,7 @@ EXPORT_SYMBOL_GPL(folio_wait_writeback_killable);
  */
 void folio_wait_stable(struct folio *folio)
 {
-       if (folio_inode(folio)->i_sb->s_iflags & SB_I_STABLE_WRITES)
+       if (mapping_stable_writes(folio_mapping(folio)))
                folio_wait_writeback(folio);
 }
 EXPORT_SYMBOL_GPL(folio_wait_stable);