* extent_writepage_io().
* This is to avoid touching ranges covered by compression/inline.
*/
- unsigned long submit_bitmap;
+ unsigned long *submit_bitmap;
+ /*
+ * When blocks_per_folio <= BITS_PER_LONG, we can use the inline
+ * one without allocating memory.
+ */
+ unsigned long submit_bitmap_value;
+
struct readahead_control *ractl;
/*
int ret = 0;
/* Save the dirty bitmap as our submission bitmap will be a subset of it. */
- bio_ctrl->submit_bitmap = btrfs_get_subpage_dirty_bitmap_value(fs_info, folio);
+ btrfs_copy_subpage_dirty_bitmap(fs_info, folio, bio_ctrl->submit_bitmap);
- for_each_set_bitrange(start_bit, end_bit, &bio_ctrl->submit_bitmap,
+ for_each_set_bitrange(start_bit, end_bit, bio_ctrl->submit_bitmap,
blocks_per_folio) {
u64 start = page_start + (start_bit << fs_info->sectorsize_bits);
u32 len = (end_bit - start_bit) << fs_info->sectorsize_bits;
btrfs_ino(inode),
folio_pos(folio),
blocks_per_folio,
- &bio_ctrl->submit_bitmap,
+ bio_ctrl->submit_bitmap,
found_start, found_len, ret);
} else {
/*
fs_info->sectorsize_bits;
unsigned int end_bit = (min(page_end + 1, found_start + found_len) -
page_start) >> fs_info->sectorsize_bits;
- bitmap_clear(&bio_ctrl->submit_bitmap, start_bit, end_bit - start_bit);
+ bitmap_clear(bio_ctrl->submit_bitmap, start_bit, end_bit - start_bit);
}
/*
* Above btrfs_run_delalloc_range() may have unlocked the folio,
fs_info->sectorsize_bits,
blocks_per_folio);
- for_each_set_bitrange(start_bit, end_bit, &bio_ctrl->submit_bitmap,
+ for_each_set_bitrange(start_bit, end_bit, bio_ctrl->submit_bitmap,
bitmap_size) {
u64 start = page_start + (start_bit << fs_info->sectorsize_bits);
u32 len = (end_bit - start_bit) << fs_info->sectorsize_bits;
* If all ranges are submitted asynchronously, we just need to account
* for them here.
*/
- if (bitmap_empty(&bio_ctrl->submit_bitmap, blocks_per_folio)) {
+ if (bitmap_empty(bio_ctrl->submit_bitmap, blocks_per_folio)) {
wbc->nr_to_write -= delalloc_to_write;
return 1;
}
loff_t i_size)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
- unsigned long range_bitmap = 0;
bool submitted_io = false;
int found_error = 0;
const u64 end = start + len;
ASSERT(end <= folio_end, "start=%llu len=%u folio_start=%llu folio_size=%zu",
start, len, folio_start, folio_size(folio));
- bitmap_set(&range_bitmap, (start - folio_pos(folio)) >> fs_info->sectorsize_bits,
- len >> fs_info->sectorsize_bits);
- bitmap_and(&bio_ctrl->submit_bitmap, &bio_ctrl->submit_bitmap, &range_bitmap,
- blocks_per_folio);
+ /* Truncate the submit bitmap to the current range. */
+ if (start > folio_start)
+ bitmap_clear(bio_ctrl->submit_bitmap, 0,
+ (start - folio_start) >> fs_info->sectorsize_bits);
+ if (start + len < folio_end)
+ bitmap_clear(bio_ctrl->submit_bitmap,
+ (end - folio_start) >> fs_info->sectorsize_bits,
+ (folio_end - end) >> fs_info->sectorsize_bits);
bio_ctrl->end_io_func = end_bbio_data_write;
- for_each_set_bit(bit, &bio_ctrl->submit_bitmap, blocks_per_folio) {
+ for_each_set_bit(bit, bio_ctrl->submit_bitmap, blocks_per_folio) {
cur = folio_pos(folio) + (bit << fs_info->sectorsize_bits);
if (cur >= i_size) {
return found_error;
}
+static void bio_ctrl_init_submit_bitmap(struct btrfs_fs_info *fs_info,
+ struct folio *folio,
+ struct btrfs_bio_ctrl *bio_ctrl)
+{
+ const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
+
+ /* Only supported for blocks per folio <= BITS_PER_LONG for now. */
+ ASSERT(blocks_per_folio <= BITS_PER_LONG);
+ bio_ctrl->submit_bitmap_value = 0;
+ bio_ctrl->submit_bitmap = &bio_ctrl->submit_bitmap_value;
+ /*
+ * Default to unlock the whole folio.
+ * The proper bitmap is not initialized until writepage_delalloc().
+ */
+ bitmap_set(bio_ctrl->submit_bitmap, 0, blocks_per_folio);
+}
+
/*
* the writepage semantics are similar to regular writepage. extent
* records are inserted to lock ranges in the tree, and as dirty areas
if (folio_contains(folio, end_index))
folio_zero_range(folio, pg_offset, folio_size(folio) - pg_offset);
- /*
- * Default to unlock the whole folio.
- * The proper bitmap can only be initialized until writepage_delalloc().
- */
- bio_ctrl->submit_bitmap = (unsigned long)-1;
-
+ bio_ctrl_init_submit_bitmap(fs_info, folio, bio_ctrl);
/*
* If the page is dirty but without private set, it's marked dirty
* without informing the fs.
"failed to submit blocks, root=%lld inode=%llu folio=%llu submit_bitmap=%*pbl: %d",
btrfs_root_id(inode->root), btrfs_ino(inode),
folio_pos(folio), blocks_per_folio,
- &bio_ctrl->submit_bitmap, ret);
+ bio_ctrl->submit_bitmap, ret);
bio_ctrl->wbc->nr_to_write--;
* Set the submission bitmap to submit all sectors.
* extent_writepage_io() will do the truncation correctly.
*/
- bio_ctrl.submit_bitmap = (unsigned long)-1;
+ bio_ctrl_init_submit_bitmap(fs_info, folio, &bio_ctrl);
ret = extent_writepage_io(BTRFS_I(inode), folio, cur, cur_len,
&bio_ctrl, i_size);
if (ret == 1)
}
void btrfs_folio_end_lock_bitmap(const struct btrfs_fs_info *fs_info,
- struct folio *folio, unsigned long bitmap)
+ struct folio *folio, unsigned long *bitmap)
{
struct btrfs_folio_state *bfs = folio_get_private(folio);
const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
- const unsigned int nbits = bitmap_weight(&bitmap, blocks_per_folio);
+ const unsigned int nbits = bitmap_weight(bitmap, blocks_per_folio);
unsigned long flags;
bool last = false;
spin_unlock_irqrestore(&bfs->lock, flags);
}
-unsigned long btrfs_get_subpage_dirty_bitmap_value(struct btrfs_fs_info *fs_info,
- struct folio *folio)
+void btrfs_copy_subpage_dirty_bitmap(struct btrfs_fs_info *fs_info,
+ struct folio *folio,
+ unsigned long *dst)
{
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;
+ if (blocks_per_folio == 1) {
+ value = 1;
+ bitmap_copy(dst, &value, 1);
+ return;
+ }
ASSERT(folio_test_private(folio) && folio_get_private(folio));
ASSERT(blocks_per_folio > 1);
- ASSERT(blocks_per_folio <= BITS_PER_LONG);
bfs = folio_get_private(folio);
+ if (blocks_per_folio <= BITS_PER_LONG) {
+ spin_lock_irqsave(&bfs->lock, flags);
+ value = bitmap_read(bfs->bitmaps, btrfs_bitmap_nr_dirty * blocks_per_folio,
+ blocks_per_folio);
+ spin_unlock_irqrestore(&bfs->lock, flags);
+ bitmap_copy(dst, &value, blocks_per_folio);
+ return;
+ }
spin_lock_irqsave(&bfs->lock, flags);
- value = get_bitmap_value_dirty(fs_info, folio);
+ bitmap_copy(dst, get_bitmap_pointer_dirty(fs_info, folio),
+ blocks_per_folio);
spin_unlock_irqrestore(&bfs->lock, flags);
- return value;
}