mm/writeback: Add filemap_dirty_folio()
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Tue, 4 May 2021 03:30:44 +0000 (23:30 -0400)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Mon, 18 Oct 2021 11:49:39 +0000 (07:49 -0400)
Reimplement __set_page_dirty_nobuffers() as a wrapper around
filemap_dirty_folio().  Eventually folio_mark_dirty() will pass
the folio's mapping to the address space's ->dirty_folio()
operation, so add the parameter to filemap_dirty_folio() now.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: David Howells <dhowells@redhat.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
include/linux/writeback.h
mm/folio-compat.c
mm/page-writeback.c

index d1f65adf6a2666388db5b7f370b15595a3930c41..d4f24eba066fd18321bd09aaf11244d4b5ef0b5f 100644 (file)
@@ -393,6 +393,7 @@ void writeback_set_ratelimit(void);
 void tag_pages_for_writeback(struct address_space *mapping,
                             pgoff_t start, pgoff_t end);
 
+bool filemap_dirty_folio(struct address_space *mapping, struct folio *folio);
 void account_page_redirty(struct page *page);
 
 void sb_mark_inode_writeback(struct inode *inode);
index 2c2b3917b5dc95b83cec2415b1dbd8287d5bc1cc..dad962b920e5e1c3e211107f42be0d9dc014b1f8 100644 (file)
@@ -83,3 +83,9 @@ bool set_page_dirty(struct page *page)
        return folio_mark_dirty(page_folio(page));
 }
 EXPORT_SYMBOL(set_page_dirty);
+
+int __set_page_dirty_nobuffers(struct page *page)
+{
+       return filemap_dirty_folio(page_mapping(page), page_folio(page));
+}
+EXPORT_SYMBOL(__set_page_dirty_nobuffers);
index ebbd15f0d8417ba19a1dae7f9a3193b84926a5e4..a501dad430af134e75b016cd666a4338af8bca39 100644 (file)
@@ -2505,41 +2505,43 @@ void __folio_mark_dirty(struct folio *folio, struct address_space *mapping,
        xa_unlock_irqrestore(&mapping->i_pages, flags);
 }
 
-/*
- * For address_spaces which do not use buffers.  Just tag the page as dirty in
- * the xarray.
- *
- * This is also used when a single buffer is being dirtied: we want to set the
- * page dirty in that case, but not all the buffers.  This is a "bottom-up"
- * dirtying, whereas __set_page_dirty_buffers() is a "top-down" dirtying.
- *
- * The caller must ensure this doesn't race with truncation.  Most will simply
- * hold the page lock, but e.g. zap_pte_range() calls with the page mapped and
- * the pte lock held, which also locks out truncation.
+/**
+ * filemap_dirty_folio - Mark a folio dirty for filesystems which do not use buffer_heads.
+ * @mapping: Address space this folio belongs to.
+ * @folio: Folio to be marked as dirty.
+ *
+ * Filesystems which do not use buffer heads should call this function
+ * from their set_page_dirty address space operation.  It ignores the
+ * contents of folio_get_private(), so if the filesystem marks individual
+ * blocks as dirty, the filesystem should handle that itself.
+ *
+ * This is also sometimes used by filesystems which use buffer_heads when
+ * a single buffer is being dirtied: we want to set the folio dirty in
+ * that case, but not all the buffers.  This is a "bottom-up" dirtying,
+ * whereas __set_page_dirty_buffers() is a "top-down" dirtying.
+ *
+ * The caller must ensure this doesn't race with truncation.  Most will
+ * simply hold the folio lock, but e.g. zap_pte_range() calls with the
+ * folio mapped and the pte lock held, which also locks out truncation.
  */
-int __set_page_dirty_nobuffers(struct page *page)
+bool filemap_dirty_folio(struct address_space *mapping, struct folio *folio)
 {
-       lock_page_memcg(page);
-       if (!TestSetPageDirty(page)) {
-               struct address_space *mapping = page_mapping(page);
+       folio_memcg_lock(folio);
+       if (folio_test_set_dirty(folio)) {
+               folio_memcg_unlock(folio);
+               return false;
+       }
 
-               if (!mapping) {
-                       unlock_page_memcg(page);
-                       return 1;
-               }
-               __set_page_dirty(page, mapping, !PagePrivate(page));
-               unlock_page_memcg(page);
+       __folio_mark_dirty(folio, mapping, !folio_test_private(folio));
+       folio_memcg_unlock(folio);
 
-               if (mapping->host) {
-                       /* !PageAnon && !swapper_space */
-                       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
-               }
-               return 1;
+       if (mapping->host) {
+               /* !PageAnon && !swapper_space */
+               __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
        }
-       unlock_page_memcg(page);
-       return 0;
+       return true;
 }
-EXPORT_SYMBOL(__set_page_dirty_nobuffers);
+EXPORT_SYMBOL(filemap_dirty_folio);
 
 /*
  * Call this whenever redirtying a page, to de-account the dirty counters