From: Joanne Koong <joannelkoong@gmail.com>
To: brauner@kernel.org
Cc: hch@infradead.org, djwong@kernel.org, bfoster@redhat.com,
linux-fsdevel@vger.kernel.org, kernel-team@meta.com
Subject: [PATCH v4 8/9] iomap: use find_next_bit() for dirty bitmap scanning
Date: Tue, 11 Nov 2025 11:36:57 -0800 [thread overview]
Message-ID: <20251111193658.3495942-9-joannelkoong@gmail.com> (raw)
In-Reply-To: <20251111193658.3495942-1-joannelkoong@gmail.com>
Use find_next_bit()/find_next_zero_bit() for iomap dirty bitmap
scanning. This uses __ffs() internally and is more efficient for
finding the next dirty or clean bit than iterating through the bitmap
range testing every bit.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Suggested-by: Christoph Hellwig <hch@infradead.org>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
fs/iomap/buffered-io.c | 61 ++++++++++++++++++++++++++++--------------
1 file changed, 41 insertions(+), 20 deletions(-)
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 98c4665addb2..1a7146d6ba49 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -76,13 +76,34 @@ static void iomap_set_range_uptodate(struct folio *folio, size_t off,
folio_mark_uptodate(folio);
}
-static inline bool ifs_block_is_dirty(struct folio *folio,
- struct iomap_folio_state *ifs, int block)
+/*
+ * Find the next dirty block in the folio. end_blk is inclusive.
+ * If no dirty block is found, this will return end_blk + 1.
+ */
+static unsigned ifs_next_dirty_block(struct folio *folio,
+ unsigned start_blk, unsigned end_blk)
{
+ struct iomap_folio_state *ifs = folio->private;
struct inode *inode = folio->mapping->host;
- unsigned int blks_per_folio = i_blocks_per_folio(inode, folio);
+ unsigned int blks = i_blocks_per_folio(inode, folio);
+
+ return find_next_bit(ifs->state, blks + end_blk + 1,
+ blks + start_blk) - blks;
+}
+
+/*
+ * Find the next clean block in the folio. end_blk is inclusive.
+ * If no clean block is found, this will return end_blk + 1.
+ */
+static unsigned ifs_next_clean_block(struct folio *folio,
+ unsigned start_blk, unsigned end_blk)
+{
+ struct iomap_folio_state *ifs = folio->private;
+ struct inode *inode = folio->mapping->host;
+ unsigned int blks = i_blocks_per_folio(inode, folio);
- return test_bit(block + blks_per_folio, ifs->state);
+ return find_next_zero_bit(ifs->state, blks + end_blk + 1,
+ blks + start_blk) - blks;
}
static unsigned ifs_find_dirty_range(struct folio *folio,
@@ -94,18 +115,17 @@ static unsigned ifs_find_dirty_range(struct folio *folio,
offset_in_folio(folio, *range_start) >> inode->i_blkbits;
unsigned end_blk = min_not_zero(
offset_in_folio(folio, range_end) >> inode->i_blkbits,
- i_blocks_per_folio(inode, folio));
- unsigned nblks = 1;
-
- while (!ifs_block_is_dirty(folio, ifs, start_blk))
- if (++start_blk == end_blk)
- return 0;
+ i_blocks_per_folio(inode, folio)) - 1;
+ unsigned nblks;
- while (start_blk + nblks < end_blk) {
- if (!ifs_block_is_dirty(folio, ifs, start_blk + nblks))
- break;
- nblks++;
- }
+ start_blk = ifs_next_dirty_block(folio, start_blk, end_blk);
+ if (start_blk > end_blk)
+ return 0;
+ if (start_blk == end_blk)
+ nblks = 1;
+ else
+ nblks = ifs_next_clean_block(folio, start_blk + 1, end_blk) -
+ start_blk;
*range_start = folio_pos(folio) + (start_blk << inode->i_blkbits);
return nblks << inode->i_blkbits;
@@ -1167,7 +1187,7 @@ static void iomap_write_delalloc_ifs_punch(struct inode *inode,
struct folio *folio, loff_t start_byte, loff_t end_byte,
struct iomap *iomap, iomap_punch_t punch)
{
- unsigned int first_blk, last_blk, i;
+ unsigned int first_blk, last_blk;
loff_t last_byte;
u8 blkbits = inode->i_blkbits;
struct iomap_folio_state *ifs;
@@ -1186,10 +1206,11 @@ static void iomap_write_delalloc_ifs_punch(struct inode *inode,
folio_pos(folio) + folio_size(folio) - 1);
first_blk = offset_in_folio(folio, start_byte) >> blkbits;
last_blk = offset_in_folio(folio, last_byte) >> blkbits;
- for (i = first_blk; i <= last_blk; i++) {
- if (!ifs_block_is_dirty(folio, ifs, i))
- punch(inode, folio_pos(folio) + (i << blkbits),
- 1 << blkbits, iomap);
+ while ((first_blk = ifs_next_clean_block(folio, first_blk, last_blk))
+ <= last_blk) {
+ punch(inode, folio_pos(folio) + (first_blk << blkbits),
+ 1 << blkbits, iomap);
+ first_blk++;
}
}
--
2.47.3
next prev parent reply other threads:[~2025-11-11 19:38 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-11 19:36 [PATCH v4 0/9] iomap: buffered io changes Joanne Koong
2025-11-11 19:36 ` [PATCH v4 1/9] iomap: rename bytes_pending/bytes_accounted to bytes_submitted/bytes_not_submitted Joanne Koong
2025-11-11 19:36 ` [PATCH v4 2/9] iomap: account for unaligned end offsets when truncating read range Joanne Koong
2025-11-11 19:36 ` [PATCH v4 3/9] docs: document iomap writeback's iomap_finish_folio_write() requirement Joanne Koong
2025-11-11 19:36 ` [PATCH v4 4/9] iomap: optimize pending async writeback accounting Joanne Koong
2025-11-11 19:36 ` [PATCH v4 5/9] iomap: simplify ->read_folio_range() error handling for reads Joanne Koong
2025-11-17 20:46 ` Matthew Wilcox
2025-11-17 23:26 ` Joanne Koong
2025-11-11 19:36 ` [PATCH v4 6/9] iomap: simplify when reads can be skipped for writes Joanne Koong
2025-11-11 19:36 ` [PATCH v4 7/9] iomap: use loff_t for file positions and offsets in writeback code Joanne Koong
2025-11-19 3:40 ` Matthew Wilcox
2025-11-19 18:10 ` Joanne Koong
2025-11-19 18:27 ` Darrick J. Wong
2025-11-19 19:17 ` Joanne Koong
2025-11-19 19:35 ` Matthew Wilcox
2025-11-20 0:38 ` Joanne Koong
2025-11-25 9:22 ` Christian Brauner
2025-11-11 19:36 ` Joanne Koong [this message]
2025-11-11 19:36 ` [PATCH v4 9/9] iomap: use find_next_bit() for uptodate bitmap scanning Joanne Koong
2025-11-12 10:34 ` [PATCH v4 0/9] iomap: buffered io changes Christian Brauner
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=20251111193658.3495942-9-joannelkoong@gmail.com \
--to=joannelkoong@gmail.com \
--cc=bfoster@redhat.com \
--cc=brauner@kernel.org \
--cc=djwong@kernel.org \
--cc=hch@infradead.org \
--cc=kernel-team@meta.com \
--cc=linux-fsdevel@vger.kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.