Skip to content

Commit 35b6ddf

Browse files
adam900710kdave
authored andcommitted
btrfs: introduce write_one_subpage_eb() function
The new function, write_one_subpage_eb(), as a subroutine for subpage metadata write, will handle the extent buffer bio submission. The major differences between the new write_one_subpage_eb() and write_one_eb() is: - No page locking When entering write_one_subpage_eb() the page is no longer locked. We only lock the page for its status update, and unlock immediately. Now we completely rely on extent io tree locking. - Extra bitmap update along with page status update Now page dirty and writeback is controlled by btrfs_subpage::dirty_bitmap and btrfs_subpage::writeback_bitmap. They both follow the schema that any sector is dirty/writeback, then the full page gets dirty/writeback. - When to update the nr_written number Now we take a shortcut, if we have cleared the last dirty bit of the page, we update nr_written. This is not completely perfect, but should emulate the old behavior well enough. Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 2f3186d commit 35b6ddf

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

fs/btrfs/extent_io.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4197,6 +4197,56 @@ static void end_bio_extent_buffer_writepage(struct bio *bio)
41974197
bio_put(bio);
41984198
}
41994199

4200+
/*
4201+
* Unlike the work in write_one_eb(), we rely completely on extent locking.
4202+
* Page locking is only utilized at minimum to keep the VMM code happy.
4203+
*
4204+
* Caller should still call write_one_eb() other than this function directly.
4205+
* As write_one_eb() has extra preparation before submitting the extent buffer.
4206+
*/
4207+
static int write_one_subpage_eb(struct extent_buffer *eb,
4208+
struct writeback_control *wbc,
4209+
struct extent_page_data *epd)
4210+
{
4211+
struct btrfs_fs_info *fs_info = eb->fs_info;
4212+
struct page *page = eb->pages[0];
4213+
unsigned int write_flags = wbc_to_write_flags(wbc) | REQ_META;
4214+
bool no_dirty_ebs = false;
4215+
int ret;
4216+
4217+
/* clear_page_dirty_for_io() in subpage helper needs page locked */
4218+
lock_page(page);
4219+
btrfs_subpage_set_writeback(fs_info, page, eb->start, eb->len);
4220+
4221+
/* Check if this is the last dirty bit to update nr_written */
4222+
no_dirty_ebs = btrfs_subpage_clear_and_test_dirty(fs_info, page,
4223+
eb->start, eb->len);
4224+
if (no_dirty_ebs)
4225+
clear_page_dirty_for_io(page);
4226+
4227+
ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc, page,
4228+
eb->start, eb->len, eb->start - page_offset(page),
4229+
&epd->bio, end_bio_extent_buffer_writepage, 0, 0, 0,
4230+
false);
4231+
if (ret) {
4232+
btrfs_subpage_clear_writeback(fs_info, page, eb->start, eb->len);
4233+
set_btree_ioerr(page, eb);
4234+
unlock_page(page);
4235+
4236+
if (atomic_dec_and_test(&eb->io_pages))
4237+
end_extent_buffer_writeback(eb);
4238+
return -EIO;
4239+
}
4240+
unlock_page(page);
4241+
/*
4242+
* Submission finished without problem, if no range of the page is
4243+
* dirty anymore, we have submitted a page. Update nr_written in wbc.
4244+
*/
4245+
if (no_dirty_ebs)
4246+
update_nr_written(wbc, 1);
4247+
return ret;
4248+
}
4249+
42004250
static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
42014251
struct writeback_control *wbc,
42024252
struct extent_page_data *epd)
@@ -4228,6 +4278,9 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
42284278
memzero_extent_buffer(eb, start, end - start);
42294279
}
42304280

4281+
if (eb->fs_info->sectorsize < PAGE_SIZE)
4282+
return write_one_subpage_eb(eb, wbc, epd);
4283+
42314284
for (i = 0; i < num_pages; i++) {
42324285
struct page *p = eb->pages[i];
42334286

0 commit comments

Comments
 (0)