From: Joanne Koong <joannelkoong@gmail.com>
To: linux-mm@kvack.org, brauner@kernel.org
Cc: willy@infradead.org, jack@suse.cz, hch@infradead.org,
djwong@kernel.org, jlayton@kernel.org,
linux-fsdevel@vger.kernel.org, kernel-team@meta.com
Subject: [PATCH v2 05/12] mm: add filemap_dirty_folio_pages() helper
Date: Fri, 29 Aug 2025 16:39:35 -0700 [thread overview]
Message-ID: <20250829233942.3607248-6-joannelkoong@gmail.com> (raw)
In-Reply-To: <20250829233942.3607248-1-joannelkoong@gmail.com>
Add filemap_dirty_folio_pages() which is equivalent to
filemap_dirty_folio() except it takes in the number of pages in the
folio to account for as dirty when it updates internal dirty stats
instead of accounting all pages in the folio as dirty. If the folio is
already dirty, calling this function will still update the stats. As
such, the caller is responsible for ensuring no overaccounting happens.
The same caller responsibilities apply here as for filemap_dirty_folio()
(eg, should ensure this doesn't race with truncation/writeback).
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
fs/buffer.c | 4 ++--
include/linux/pagemap.h | 2 +-
include/linux/writeback.h | 2 ++
mm/page-writeback.c | 41 +++++++++++++++++++++++++++++++++++----
4 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index 65c96c432800..558591254fdb 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -752,7 +752,7 @@ bool block_dirty_folio(struct address_space *mapping, struct folio *folio)
if (newly_dirty)
__folio_mark_dirty(folio, mapping, 1,
- folio_nr_pages(folio));
+ folio_nr_pages(folio), true);
if (newly_dirty)
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
@@ -1205,7 +1205,7 @@ void mark_buffer_dirty(struct buffer_head *bh)
mapping = folio->mapping;
if (mapping)
__folio_mark_dirty(folio, mapping, 0,
- folio_nr_pages(folio));
+ folio_nr_pages(folio), true);
}
if (mapping)
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 48745f8f6dfe..510bc6e0f70b 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -1224,7 +1224,7 @@ void folio_end_writeback(struct folio *folio);
void folio_end_writeback_pages(struct folio *folio, long nr_pages);
void folio_wait_stable(struct folio *folio);
void __folio_mark_dirty(struct folio *folio, struct address_space *, int warn,
- long nr_pages);
+ long nr_pages, bool newly_dirty);
void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb);
void __folio_cancel_dirty(struct folio *folio);
static inline void folio_cancel_dirty(struct folio *folio)
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index a2848d731a46..0df11d00cce2 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -372,6 +372,8 @@ 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);
+bool filemap_dirty_folio_pages(struct address_space *mapping,
+ struct folio *folio, long nr_pages);
bool folio_redirty_for_writepage(struct writeback_control *, struct folio *);
bool redirty_page_for_writepage(struct writeback_control *, struct page *);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index e66eef2d1584..1f862ab3c68d 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2730,7 +2730,7 @@ void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb)
* try_to_free_buffers() to fail.
*/
void __folio_mark_dirty(struct folio *folio, struct address_space *mapping,
- int warn, long nr_pages)
+ int warn, long nr_pages, bool newly_dirty)
{
unsigned long flags;
@@ -2738,8 +2738,9 @@ void __folio_mark_dirty(struct folio *folio, struct address_space *mapping,
if (folio->mapping) { /* Race with truncate? */
WARN_ON_ONCE(warn && !folio_test_uptodate(folio));
folio_account_dirtied(folio, mapping, nr_pages);
- __xa_set_mark(&mapping->i_pages, folio_index(folio),
- PAGECACHE_TAG_DIRTY);
+ if (newly_dirty)
+ __xa_set_mark(&mapping->i_pages, folio_index(folio),
+ PAGECACHE_TAG_DIRTY);
}
xa_unlock_irqrestore(&mapping->i_pages, flags);
}
@@ -2769,7 +2770,7 @@ bool filemap_dirty_folio(struct address_space *mapping, struct folio *folio)
return false;
__folio_mark_dirty(folio, mapping, !folio_test_private(folio),
- folio_nr_pages(folio));
+ folio_nr_pages(folio), true);
if (mapping->host) {
/* !PageAnon && !swapper_space */
@@ -2779,6 +2780,38 @@ bool filemap_dirty_folio(struct address_space *mapping, struct folio *folio)
}
EXPORT_SYMBOL(filemap_dirty_folio);
+/**
+ * filemap_dirty_folio_pages - Mark a folio dirty and update stats to account
+ * for dirtying @nr_pages within the folio.
+ * @mapping: Address space this folio belongs to.
+ * @folio: Folio to be marked as dirty.
+ * @nr_pages: Number of pages to dirty.
+ *
+ * This is equivalent to filemap_dirty_folio() except it takes in the number of
+ * pages in the folio to account for as dirty when it updates internal dirty
+ * stats instead of accounting all pages in the folio as dirty. If the folio is
+ * already dirty, calling this function will still update the stats. As such,
+ * the caller is responsible for ensuring no overaccounting happens.
+ *
+ * The same caller responsibilities apply here as for filemap_dirty_folio()
+ * (eg, should ensure this doesn't race with truncation/writeback).
+ */
+bool filemap_dirty_folio_pages(struct address_space *mapping,
+ struct folio *folio, long nr_pages)
+{
+ bool newly_dirty = !folio_test_set_dirty(folio);
+
+ __folio_mark_dirty(folio, mapping, !folio_test_private(folio),
+ nr_pages, newly_dirty);
+
+ if (newly_dirty && mapping->host) {
+ /* !PageAnon && !swapper_space */
+ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+ }
+
+ return newly_dirty;
+}
+
/**
* folio_redirty_for_writepage - Decline to write a dirty folio.
* @wbc: The writeback control.
--
2.47.3
next prev parent reply other threads:[~2025-08-29 23:40 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-29 23:39 [PATCH v2 00/12] mm/iomap: add granular dirty and writeback accounting Joanne Koong
2025-08-29 23:39 ` [PATCH v2 01/12] mm: pass number of pages to __folio_start_writeback() Joanne Koong
2025-09-03 11:48 ` David Hildenbrand
2025-09-03 20:02 ` Darrick J. Wong
2025-09-03 20:05 ` David Hildenbrand
2025-09-03 23:12 ` Joanne Koong
2025-08-29 23:39 ` [PATCH v2 02/12] mm: pass number of pages to __folio_end_writeback() Joanne Koong
2025-08-29 23:39 ` [PATCH v2 03/12] mm: add folio_end_writeback_pages() helper Joanne Koong
2025-08-29 23:39 ` [PATCH v2 04/12] mm: pass number of pages dirtied to __folio_mark_dirty() Joanne Koong
2025-08-29 23:39 ` Joanne Koong [this message]
2025-08-29 23:39 ` [PATCH v2 06/12] mm: add __folio_clear_dirty_for_io() helper Joanne Koong
2025-08-29 23:39 ` [PATCH v2 07/12] mm: add no_stats_accounting bitfield to wbc Joanne Koong
2025-08-29 23:39 ` [PATCH v2 08/12] mm: refactor clearing dirty stats into helper function Joanne Koong
2025-08-29 23:39 ` [PATCH v2 09/12] mm: add clear_dirty_for_io_stats() helper Joanne Koong
2025-08-29 23:39 ` [PATCH v2 10/12] iomap: refactor dirty bitmap iteration Joanne Koong
2025-09-03 18:53 ` Brian Foster
2025-09-03 19:59 ` Darrick J. Wong
2025-10-03 22:27 ` Joanne Koong
2025-10-04 1:11 ` Joanne Koong
2025-08-29 23:39 ` [PATCH v2 11/12] iomap: refactor uptodate " Joanne Koong
2025-08-29 23:39 ` [PATCH v2 12/12] iomap: add granular dirty and writeback accounting Joanne Koong
2025-09-02 23:46 ` Darrick J. Wong
2025-09-03 18:48 ` Brian Foster
2025-09-04 0:35 ` Joanne Koong
2025-09-04 2:52 ` Darrick J. Wong
2025-09-04 11:47 ` Brian Foster
2025-09-04 20:07 ` Darrick J. Wong
2025-09-05 0:14 ` Joanne Koong
2025-09-05 11:19 ` Brian Foster
2025-09-05 12:43 ` Jan Kara
2025-09-05 23:30 ` Joanne Koong
2025-09-04 8:53 ` [PATCH v2 00/12] mm/iomap: " Jan Kara
2025-09-04 23:59 ` Joanne Koong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250829233942.3607248-6-joannelkoong@gmail.com \
--to=joannelkoong@gmail.com \
--cc=brauner@kernel.org \
--cc=djwong@kernel.org \
--cc=hch@infradead.org \
--cc=jack@suse.cz \
--cc=jlayton@kernel.org \
--cc=kernel-team@meta.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox