btrfs: remove folio ordered flag and subpage bitmap

Btrfs has an internal flag/subpage bitmap called ordered, which is to
indicate that a block has corresponding ordered extent covering it.

However this requires extra synchronization between the inode ordered
tree, and the folio flag/subpage bitmap, not to mention we need to
maintain the extra folio flag with subpage bitmap.

As a step to align btrfs_folio_state more closely to iomap_folio_state,
remove the btrfs specific ordered flag/bitmap.

This will also save us 64 bytes for the bitmap of a huge folio.

Since we're here, also update the ASCII graph of the bitmap, as there
are only 3 sub-bitmaps now, show all sub-bitmaps directly.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2026-05-13 08:06:38 +09:30 committed by David Sterba
parent aea704836e
commit 4927b14187
6 changed files with 7 additions and 91 deletions

View File

@ -250,8 +250,6 @@ static void process_one_folio(struct btrfs_fs_info *fs_info,
ASSERT(end + 1 - start != 0 && end + 1 - start < U32_MAX);
len = end + 1 - start;
if (page_ops & PAGE_SET_ORDERED)
btrfs_folio_clamp_set_ordered(fs_info, folio, start, len);
if (page_ops & PAGE_START_WRITEBACK) {
btrfs_folio_clamp_clear_dirty(fs_info, folio, start, len);
btrfs_folio_clamp_set_writeback(fs_info, folio, start, len);
@ -530,7 +528,6 @@ static void end_bbio_data_write(struct btrfs_bio *bbio)
u32 len = fi.length;
bio_size += len;
btrfs_folio_clear_ordered(fs_info, folio, start, len);
btrfs_folio_clear_writeback(fs_info, folio, start, len);
}
@ -1629,7 +1626,6 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
u64 start = page_start + (start_bit << fs_info->sectorsize_bits);
u32 len = (end_bit - start_bit) << fs_info->sectorsize_bits;
btrfs_folio_clear_ordered(fs_info, folio, start, len);
btrfs_mark_ordered_io_finished(inode, start, len, false);
}
return ret;
@ -1707,7 +1703,6 @@ static int submit_one_sector(struct btrfs_inode *inode,
* ordered extent.
*/
btrfs_folio_clear_dirty(fs_info, folio, filepos, sectorsize);
btrfs_folio_clear_ordered(fs_info, folio, filepos, sectorsize);
btrfs_folio_set_writeback(fs_info, folio, filepos, sectorsize);
btrfs_folio_clear_writeback(fs_info, folio, filepos, sectorsize);
@ -1756,7 +1751,6 @@ static int submit_one_sector(struct btrfs_inode *inode,
sectorsize, filepos - folio_pos(folio), 0);
if (unlikely(queued < sectorsize)) {
btrfs_folio_clear_writeback(fs_info, folio, filepos, sectorsize);
btrfs_folio_clear_ordered(fs_info, folio, filepos, sectorsize);
btrfs_mark_ordered_io_finished(inode, filepos, fs_info->sectorsize,
false);
return -EUCLEAN;
@ -1821,7 +1815,6 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode,
spin_unlock(&inode->ordered_tree_lock);
btrfs_put_ordered_extent(ordered);
btrfs_folio_clear_ordered(fs_info, folio, cur, fs_info->sectorsize);
btrfs_mark_ordered_io_finished(inode, cur, fs_info->sectorsize, true);
/*
* This range is beyond i_size, thus we don't need to

View File

@ -55,7 +55,6 @@ enum {
/* Page starts writeback, clear dirty bit and set writeback bit */
ENUM_BIT(PAGE_START_WRITEBACK),
ENUM_BIT(PAGE_END_WRITEBACK),
ENUM_BIT(PAGE_SET_ORDERED),
};
/*

View File

@ -1198,14 +1198,6 @@ static inline void btrfs_force_shutdown(struct btrfs_fs_info *fs_info)
}
}
/*
* We use folio flag owner_2 to indicate there is an ordered extent with
* unfinished IO.
*/
#define folio_test_ordered(folio) folio_test_owner_2(folio)
#define folio_set_ordered(folio) folio_set_owner_2(folio)
#define folio_clear_ordered(folio) folio_clear_owner_2(folio)
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
#define EXPORT_FOR_TESTS

View File

@ -401,28 +401,6 @@ void btrfs_inode_unlock(struct btrfs_inode *inode, unsigned int ilock_flags)
static inline void btrfs_cleanup_ordered_extents(struct btrfs_inode *inode,
u64 offset, u64 bytes)
{
pgoff_t index = offset >> PAGE_SHIFT;
const pgoff_t end_index = (offset + bytes - 1) >> PAGE_SHIFT;
struct folio *folio;
while (index <= end_index) {
folio = filemap_get_folio(inode->vfs_inode.i_mapping, index);
if (IS_ERR(folio)) {
index++;
continue;
}
index = folio_next_index(folio);
/*
* Here we just clear all Ordered bits for every page in the
* range, then btrfs_mark_ordered_io_finished() will handle
* the ordered extent accounting for the range.
*/
btrfs_folio_clamp_clear_ordered(inode->root->fs_info, folio,
offset, bytes);
folio_put(folio);
}
return btrfs_mark_ordered_io_finished(inode, offset, bytes, false);
}
@ -1406,7 +1384,6 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
* setup for writepage.
*/
page_ops = ((flags & COW_FILE_RANGE_KEEP_LOCKED) ? 0 : PAGE_UNLOCK);
page_ops |= PAGE_SET_ORDERED;
/*
* Relocation relies on the relocated extents to have exactly the same
@ -1972,8 +1949,7 @@ static int nocow_one_range(struct btrfs_inode *inode, struct folio *locked_folio
goto error;
extent_clear_unlock_delalloc(inode, file_pos, end, locked_folio, cached,
EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_CLEAR_DATA_RESV,
PAGE_SET_ORDERED);
EXTENT_CLEAR_DATA_RESV, 0);
return ret;
error:
@ -7600,10 +7576,7 @@ static void btrfs_invalidate_folio(struct folio *folio, size_t offset,
* The range is dirty meaning it has not been submitted.
* Here we need to truncate the OE range as the range will never
* be submitted.
*/
btrfs_folio_clear_ordered(fs_info, folio, cur, range_len);
/*
*
* IO on this page will never be started, so we need to account
* for any ordered extents now. Don't clear EXTENT_DELALLOC_NEW
* here, must leave that up for the ordered extent completion.

View File

@ -465,35 +465,6 @@ void btrfs_subpage_clear_writeback(const struct btrfs_fs_info *fs_info,
spin_unlock_irqrestore(&bfs->lock, flags);
}
void btrfs_subpage_set_ordered(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
struct btrfs_folio_state *bfs = folio_get_private(folio);
unsigned int start_bit = subpage_calc_start_bit(fs_info, folio,
ordered, start, len);
unsigned long flags;
spin_lock_irqsave(&bfs->lock, flags);
bitmap_set(bfs->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
folio_set_ordered(folio);
spin_unlock_irqrestore(&bfs->lock, flags);
}
void btrfs_subpage_clear_ordered(const struct btrfs_fs_info *fs_info,
struct folio *folio, u64 start, u32 len)
{
struct btrfs_folio_state *bfs = folio_get_private(folio);
unsigned int start_bit = subpage_calc_start_bit(fs_info, folio,
ordered, start, len);
unsigned long flags;
spin_lock_irqsave(&bfs->lock, flags);
bitmap_clear(bfs->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
if (subpage_test_bitmap_all_zero(fs_info, folio, ordered))
folio_clear_ordered(folio);
spin_unlock_irqrestore(&bfs->lock, flags);
}
/*
* Unlike set/clear which is dependent on each page status, for test all bits
* are tested in the same way.
@ -517,7 +488,6 @@ bool btrfs_subpage_test_##name(const struct btrfs_fs_info *fs_info, \
IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(uptodate);
IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(dirty);
IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(writeback);
IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(ordered);
/*
* Note that, in selftests (extent-io-tests), we can have empty fs_info passed
@ -613,8 +583,6 @@ IMPLEMENT_BTRFS_PAGE_OPS(dirty, folio_mark_dirty, folio_clear_dirty_for_io,
folio_test_dirty);
IMPLEMENT_BTRFS_PAGE_OPS(writeback, folio_start_writeback, folio_end_writeback,
folio_test_writeback);
IMPLEMENT_BTRFS_PAGE_OPS(ordered, folio_set_ordered, folio_clear_ordered,
folio_test_ordered);
#define GET_SUBPAGE_BITMAP(fs_info, folio, name, dst) \
{ \
@ -727,7 +695,6 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
unsigned long uptodate_bitmap;
unsigned long dirty_bitmap;
unsigned long writeback_bitmap;
unsigned long ordered_bitmap;
unsigned long flags;
ASSERT(folio_test_private(folio) && folio_get_private(folio));
@ -738,17 +705,15 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
GET_SUBPAGE_BITMAP(fs_info, folio, uptodate, &uptodate_bitmap);
GET_SUBPAGE_BITMAP(fs_info, folio, dirty, &dirty_bitmap);
GET_SUBPAGE_BITMAP(fs_info, folio, writeback, &writeback_bitmap);
GET_SUBPAGE_BITMAP(fs_info, folio, ordered, &ordered_bitmap);
spin_unlock_irqrestore(&bfs->lock, flags);
dump_page(folio_page(folio, 0), "btrfs folio state dump");
btrfs_warn(fs_info,
"start=%llu len=%u page=%llu, bitmaps uptodate=%*pbl dirty=%*pbl writeback=%*pbl ordered=%*pbl",
"start=%llu len=%u page=%llu, bitmaps uptodate=%*pbl dirty=%*pbl writeback=%*pbl",
start, len, folio_pos(folio),
blocks_per_folio, &uptodate_bitmap,
blocks_per_folio, &dirty_bitmap,
blocks_per_folio, &writeback_bitmap,
blocks_per_folio, &ordered_bitmap);
blocks_per_folio, &writeback_bitmap);
}
void btrfs_get_subpage_dirty_bitmap(struct btrfs_fs_info *fs_info,

View File

@ -14,15 +14,15 @@ struct folio;
/*
* Extra info for subpage bitmap.
*
* For subpage we pack all uptodate/dirty/writeback/ordered bitmaps into
* For subpage we pack all uptodate/dirty/writeback bitmaps into
* one larger bitmap.
*
* This structure records how they are organized in the bitmap:
*
* /- uptodate /- dirty /- ordered
* /- uptodate /- dirty /- writeback
* | | |
* v v v
* |u|u|u|u|........|u|u|d|d|.......|d|d|o|o|.......|o|o|
* |u|u|u|u|........|u|u|d|d|.......|d|d|w|w|.......|w|w|
* |< sectors_per_page >|
*
* Unlike regular macro-like enums, here we do not go upper-case names, as
@ -40,11 +40,6 @@ enum {
*/
btrfs_bitmap_nr_writeback,
/*
* The ordered flags shows if the range has an ordered extent.
*/
btrfs_bitmap_nr_ordered,
btrfs_bitmap_nr_max
};
@ -169,7 +164,6 @@ bool btrfs_meta_folio_test_##name(struct folio *folio, const struct extent_buffe
DECLARE_BTRFS_SUBPAGE_OPS(uptodate);
DECLARE_BTRFS_SUBPAGE_OPS(dirty);
DECLARE_BTRFS_SUBPAGE_OPS(writeback);
DECLARE_BTRFS_SUBPAGE_OPS(ordered);
/*
* Helper for error cleanup, where a folio will have its dirty flag cleared,