mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
btrfs: subpage: make reader lock utilize bitmap
Currently btrfs_subpage utilizes its atomic member @reader to manage the reader counter. However it is only utilized to prevent the page to be released/unlocked when we still have reads underway. In that use case, we don't really allow multiple readers on the same subpage sector. So here we can introduce a new locked bitmap to represent exactly which subpage range is locked for read. In theory we can remove btrfs_subpage::reader as it's just the set bits of the new locked bitmap. But unfortunately bitmap doesn't provide such handy API yet, so we still keep the reader counter. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
621b9ff18c
commit
8e7e9c672f
@ -111,6 +111,9 @@ void btrfs_init_subpage_info(struct btrfs_subpage_info *subpage_info, u32 sector
|
||||
subpage_info->checked_offset = cur;
|
||||
cur += nr_bits;
|
||||
|
||||
subpage_info->locked_offset = cur;
|
||||
cur += nr_bits;
|
||||
|
||||
subpage_info->total_nr_bits = cur;
|
||||
}
|
||||
|
||||
@ -237,28 +240,58 @@ static void btrfs_subpage_assert(const struct btrfs_fs_info *fs_info,
|
||||
start + len <= folio_pos(folio) + PAGE_SIZE);
|
||||
}
|
||||
|
||||
#define subpage_calc_start_bit(fs_info, folio, name, start, len) \
|
||||
({ \
|
||||
unsigned int start_bit; \
|
||||
\
|
||||
btrfs_subpage_assert(fs_info, folio, start, len); \
|
||||
start_bit = offset_in_page(start) >> fs_info->sectorsize_bits; \
|
||||
start_bit += fs_info->subpage_info->name##_offset; \
|
||||
start_bit; \
|
||||
})
|
||||
|
||||
void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, u64 start, u32 len)
|
||||
{
|
||||
struct btrfs_subpage *subpage = folio_get_private(folio);
|
||||
const int start_bit = subpage_calc_start_bit(fs_info, folio, locked, start, len);
|
||||
const int nbits = len >> fs_info->sectorsize_bits;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
btrfs_subpage_assert(fs_info, folio, start, len);
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
/*
|
||||
* Even though it's just for reading the page, no one should have
|
||||
* locked the subpage range.
|
||||
*/
|
||||
ASSERT(bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits));
|
||||
bitmap_set(subpage->bitmaps, start_bit, nbits);
|
||||
atomic_add(nbits, &subpage->readers);
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
}
|
||||
|
||||
void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, u64 start, u32 len)
|
||||
{
|
||||
struct btrfs_subpage *subpage = folio_get_private(folio);
|
||||
const int start_bit = subpage_calc_start_bit(fs_info, folio, locked, start, len);
|
||||
const int nbits = len >> fs_info->sectorsize_bits;
|
||||
unsigned long flags;
|
||||
bool is_data;
|
||||
bool last;
|
||||
|
||||
btrfs_subpage_assert(fs_info, folio, start, len);
|
||||
is_data = is_data_inode(folio->mapping->host);
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
|
||||
/* The range should have already been locked. */
|
||||
ASSERT(bitmap_test_range_all_set(subpage->bitmaps, start_bit, nbits));
|
||||
ASSERT(atomic_read(&subpage->readers) >= nbits);
|
||||
|
||||
bitmap_clear(subpage->bitmaps, start_bit, nbits);
|
||||
last = atomic_sub_and_test(nbits, &subpage->readers);
|
||||
|
||||
/*
|
||||
@ -270,6 +303,7 @@ void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
|
||||
*/
|
||||
if (is_data && last)
|
||||
folio_unlock(folio);
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
}
|
||||
|
||||
static void btrfs_subpage_clamp_range(struct folio *folio, u64 *start, u32 *len)
|
||||
@ -365,16 +399,6 @@ void btrfs_folio_end_writer_lock(const struct btrfs_fs_info *fs_info,
|
||||
folio_unlock(folio);
|
||||
}
|
||||
|
||||
#define subpage_calc_start_bit(fs_info, folio, name, start, len) \
|
||||
({ \
|
||||
unsigned int start_bit; \
|
||||
\
|
||||
btrfs_subpage_assert(fs_info, folio, start, len); \
|
||||
start_bit = offset_in_page(start) >> fs_info->sectorsize_bits; \
|
||||
start_bit += fs_info->subpage_info->name##_offset; \
|
||||
start_bit; \
|
||||
})
|
||||
|
||||
#define subpage_test_bitmap_all_set(fs_info, subpage, name) \
|
||||
bitmap_test_range_all_set(subpage->bitmaps, \
|
||||
fs_info->subpage_info->name##_offset, \
|
||||
@ -751,6 +775,7 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
|
||||
GET_SUBPAGE_BITMAP(subpage, subpage_info, writeback, &writeback_bitmap);
|
||||
GET_SUBPAGE_BITMAP(subpage, subpage_info, ordered, &ordered_bitmap);
|
||||
GET_SUBPAGE_BITMAP(subpage, subpage_info, checked, &checked_bitmap);
|
||||
GET_SUBPAGE_BITMAP(subpage, subpage_info, locked, &checked_bitmap);
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
|
||||
dump_page(folio_page(folio, 0), "btrfs subpage dump");
|
||||
|
@ -33,7 +33,7 @@ struct btrfs_subpage_info {
|
||||
unsigned int total_nr_bits;
|
||||
|
||||
/*
|
||||
* *_start indicates where the bitmap starts, the length is always
|
||||
* *_offset indicates where the bitmap starts, the length is always
|
||||
* @bitmap_size, which is calculated from PAGE_SIZE / sectorsize.
|
||||
*/
|
||||
unsigned int uptodate_offset;
|
||||
@ -41,6 +41,16 @@ struct btrfs_subpage_info {
|
||||
unsigned int writeback_offset;
|
||||
unsigned int ordered_offset;
|
||||
unsigned int checked_offset;
|
||||
|
||||
/*
|
||||
* For locked bitmaps, normally it's subpage representation for folio
|
||||
* Locked flag, but metadata is different:
|
||||
*
|
||||
* - Metadata doesn't really lock the folio
|
||||
* It's just to prevent page::private get cleared before the last
|
||||
* end_page_read().
|
||||
*/
|
||||
unsigned int locked_offset;
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user