mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 18:21:24 +02:00
btrfs: prepare subpage operations to support more than BITS_PER_LONG sub-bitmaps
[CURRENT LIMIT] Btrfs currently only supports sub-bitmaps (e.g. dirty bitmap) no larger than BITS_PER_LONG. That limit allows us to easily grab an unsigned long without the need to properly allocate memory for a larger bitmap. Unfortunately that limit prevents us from supporting huge folios. For 4K page size and block size, a huge folio (order 9) means 512 blocks inside a 2M folio. [ENHANCEMENT] To allow direct bitmap operations without allocating new memory, introduce two different ways to access the subpage bitmaps: - Return an unsigned long value This only happens if blocks_per_folio <= BITS_PER_LONG. We read out the sub-bitmap into an unsigned long, and return the value. This is the old existing method. This involves get_bitmap_value_##name() helper functions. And this time the helper functions are defined as inline functions instead of macros to provide better type checks. - Return a pointer where the sub-bitmap starts This only happens if blocks_per_folio >= BITS_PER_LONG. This is the new method for sub-bitmaps larger than BITS_PER_LONG. Since the sizes of sub-bitmaps are all aligned to BITS_PER_LONG, we can directly access the start word of the sub-bitmap. This involves get_bitmap_pointer_##name() helper functions. Then change the existing sub-bitmaps users to use the new helpers: - Bitmap dumping Switch between get_bitmap_value_##name() and get_bitmap_pointer_##name() depending on the sub-bitmap size. - btrfs_get_subpage_dirty_bitmap() Rename it to btrfs_get_subpage_dirty_bitmap_value() to follow the new value/pointer naming. Since we do not support huge folios yet, there is no pointer version for the dirty bitmap. Furthermore, add the support for block size == page size cases for btrfs_get_subpage_dirty_bitmap_value(), so that the caller no longer needs to check if the folio needs subpage handling. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
a93a87780d
commit
eb6915bb86
|
|
@ -1492,12 +1492,7 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
|
|||
int ret = 0;
|
||||
|
||||
/* Save the dirty bitmap as our submission bitmap will be a subset of it. */
|
||||
if (btrfs_is_subpage(fs_info, folio)) {
|
||||
ASSERT(blocks_per_folio > 1);
|
||||
btrfs_get_subpage_dirty_bitmap(fs_info, folio, &bio_ctrl->submit_bitmap);
|
||||
} else {
|
||||
bio_ctrl->submit_bitmap = 1;
|
||||
}
|
||||
bio_ctrl->submit_bitmap = btrfs_get_subpage_dirty_bitmap_value(fs_info, folio);
|
||||
|
||||
for_each_set_bitrange(start_bit, end_bit, &bio_ctrl->submit_bitmap,
|
||||
blocks_per_folio) {
|
||||
|
|
|
|||
|
|
@ -555,25 +555,54 @@ IMPLEMENT_BTRFS_PAGE_OPS(dirty, folio_mark_dirty, folio_clear_dirty_for_io,
|
|||
IMPLEMENT_BTRFS_PAGE_OPS(writeback, folio_start_writeback, folio_end_writeback,
|
||||
folio_test_writeback);
|
||||
|
||||
#define GET_SUBPAGE_BITMAP(fs_info, folio, name, dst) \
|
||||
{ \
|
||||
const unsigned int __bpf = btrfs_blocks_per_folio(fs_info, folio); \
|
||||
const struct btrfs_folio_state *__bfs = folio_get_private(folio); \
|
||||
\
|
||||
ASSERT(__bpf <= BITS_PER_LONG); \
|
||||
*dst = bitmap_read(__bfs->bitmaps, \
|
||||
__bpf * btrfs_bitmap_nr_##name, __bpf); \
|
||||
#define DEFINE_GET_SUBPAGE_BITMAP(name) \
|
||||
static inline unsigned long get_bitmap_value_##name( \
|
||||
const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio) \
|
||||
{ \
|
||||
const unsigned int __bpf = btrfs_blocks_per_folio(fs_info, folio); \
|
||||
const struct btrfs_folio_state *__bfs = folio_get_private(folio); \
|
||||
unsigned long value; \
|
||||
\
|
||||
ASSERT(__bpf <= BITS_PER_LONG); \
|
||||
value = bitmap_read(__bfs->bitmaps, __bpf * btrfs_bitmap_nr_##name, \
|
||||
__bpf); \
|
||||
return value; \
|
||||
} \
|
||||
static inline const unsigned long *get_bitmap_pointer_##name( \
|
||||
const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio) \
|
||||
{ \
|
||||
const unsigned int __bpf = btrfs_blocks_per_folio(fs_info, folio); \
|
||||
struct btrfs_folio_state *__bfs = folio_get_private(folio); \
|
||||
unsigned long *pointer; \
|
||||
\
|
||||
ASSERT(__bpf >= BITS_PER_LONG); \
|
||||
ASSERT(IS_ALIGNED(__bpf, BITS_PER_LONG)); \
|
||||
pointer = __bfs->bitmaps + (BIT_WORD(__bpf) * btrfs_bitmap_nr_##name); \
|
||||
return pointer; \
|
||||
}
|
||||
|
||||
#define SUBPAGE_DUMP_BITMAP(fs_info, folio, name, start, len) \
|
||||
{ \
|
||||
unsigned long bitmap; \
|
||||
const unsigned int __bpf = btrfs_blocks_per_folio(fs_info, folio); \
|
||||
\
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, name, &bitmap); \
|
||||
btrfs_warn(fs_info, \
|
||||
"dumping bitmap start=%llu len=%u folio=%llu " #name "_bitmap=%*pbl", \
|
||||
start, len, folio_pos(folio), __bpf, &bitmap); \
|
||||
DEFINE_GET_SUBPAGE_BITMAP(uptodate);
|
||||
DEFINE_GET_SUBPAGE_BITMAP(dirty);
|
||||
DEFINE_GET_SUBPAGE_BITMAP(writeback);
|
||||
|
||||
#define SUBPAGE_DUMP_BITMAP(fs_info, folio, name, start, len) \
|
||||
{ \
|
||||
const unsigned int __bpf = btrfs_blocks_per_folio(fs_info, folio); \
|
||||
\
|
||||
if (__bpf <= BITS_PER_LONG) { \
|
||||
unsigned long bitmap = get_bitmap_value_##name(fs_info, folio); \
|
||||
\
|
||||
btrfs_warn(fs_info, \
|
||||
"dumping bitmap start=%llu len=%u folio=%llu " #name "_bitmap=%*pbl", \
|
||||
start, len, folio_pos(folio), __bpf, &bitmap); \
|
||||
} else { \
|
||||
btrfs_warn(fs_info, \
|
||||
"dumping bitmap start=%llu len=%u folio=%llu " #name "_bitmap=%*pbl", \
|
||||
start, len, folio_pos(folio), __bpf, \
|
||||
get_bitmap_pointer_##name(fs_info, folio)); \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -663,42 +692,63 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
|
|||
{
|
||||
struct btrfs_folio_state *bfs;
|
||||
const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
|
||||
unsigned long uptodate_bitmap;
|
||||
unsigned long dirty_bitmap;
|
||||
unsigned long writeback_bitmap;
|
||||
unsigned long flags;
|
||||
|
||||
ASSERT(folio_test_private(folio) && folio_get_private(folio));
|
||||
ASSERT(blocks_per_folio > 1);
|
||||
bfs = folio_get_private(folio);
|
||||
|
||||
spin_lock_irqsave(&bfs->lock, flags);
|
||||
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);
|
||||
spin_unlock_irqrestore(&bfs->lock, flags);
|
||||
|
||||
dump_page(folio_page(folio, 0), "btrfs folio state dump");
|
||||
|
||||
if (blocks_per_folio <= BITS_PER_LONG) {
|
||||
unsigned long uptodate;
|
||||
unsigned long dirty;
|
||||
unsigned long writeback;
|
||||
|
||||
spin_lock_irqsave(&bfs->lock, flags);
|
||||
uptodate = get_bitmap_value_uptodate(fs_info, folio);
|
||||
dirty = get_bitmap_value_dirty(fs_info, folio);
|
||||
writeback = get_bitmap_value_writeback(fs_info, folio);
|
||||
|
||||
spin_unlock_irqrestore(&bfs->lock, flags);
|
||||
|
||||
btrfs_warn(fs_info,
|
||||
"start=%llu len=%u page=%llu, bitmaps uptodate=%*pbl dirty=%*pbl writeback=%*pbl",
|
||||
start, len, folio_pos(folio),
|
||||
blocks_per_folio, &uptodate,
|
||||
blocks_per_folio, &dirty,
|
||||
blocks_per_folio, &writeback);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&bfs->lock, flags);
|
||||
btrfs_warn(fs_info,
|
||||
"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, get_bitmap_pointer_uptodate(fs_info, folio),
|
||||
blocks_per_folio, get_bitmap_pointer_dirty(fs_info, folio),
|
||||
blocks_per_folio, get_bitmap_pointer_writeback(fs_info, folio));
|
||||
spin_unlock_irqrestore(&bfs->lock, flags);
|
||||
}
|
||||
|
||||
void btrfs_get_subpage_dirty_bitmap(struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio,
|
||||
unsigned long *ret_bitmap)
|
||||
unsigned long btrfs_get_subpage_dirty_bitmap_value(struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio)
|
||||
{
|
||||
struct btrfs_folio_state *bfs;
|
||||
const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
|
||||
unsigned long flags;
|
||||
unsigned long value;
|
||||
|
||||
if (blocks_per_folio == 1)
|
||||
return 1;
|
||||
|
||||
ASSERT(folio_test_private(folio) && folio_get_private(folio));
|
||||
ASSERT(btrfs_blocks_per_folio(fs_info, folio) > 1);
|
||||
ASSERT(blocks_per_folio > 1);
|
||||
ASSERT(blocks_per_folio <= BITS_PER_LONG);
|
||||
bfs = folio_get_private(folio);
|
||||
|
||||
spin_lock_irqsave(&bfs->lock, flags);
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, dirty, ret_bitmap);
|
||||
value = get_bitmap_value_dirty(fs_info, folio);
|
||||
spin_unlock_irqrestore(&bfs->lock, flags);
|
||||
return value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,9 +184,8 @@ bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info,
|
|||
void btrfs_folio_assert_not_dirty(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, u64 start, u32 len);
|
||||
bool btrfs_meta_folio_clear_and_test_dirty(struct folio *folio, const struct extent_buffer *eb);
|
||||
void btrfs_get_subpage_dirty_bitmap(struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio,
|
||||
unsigned long *ret_bitmap);
|
||||
unsigned long btrfs_get_subpage_dirty_bitmap_value(struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio);
|
||||
void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, u64 start, u32 len);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user