From a8366d32414fdc99394f0739c38426461edf4639 Mon Sep 17 00:00:00 2001 From: Xiaoguang Wang Date: Tue, 25 Dec 2018 15:56:39 +0800 Subject: [PATCH] alios: ext4: don't submit unwritten extent while holding active jbd2 handle In ext4_writepages(), for every iteration, mpage_prepare_extent_to_map() will try to find 2048 pages to map and normally one bio can contain 256 pages at most. If we really found 2048 pages to map, there will be 4 bios and 4 ext4_io_submit() calls which are called both in ext4_writepages() and mpage_map_and_submit_extent(). But note that in mpage_map_and_submit_extent(), we hold a valid jbd2 handle, when dioread_nolock is enabled and extent is unwritten, jbd2 commit thread will wait this handle to finish, so wait the unwritten extent is written to disk, this will introduce unnecessary stall time, especially longer when the writeback operation is io throttled, need to fix this issue. Here for this scene, we accumulate bios in ext4_io_submit's io_bio, and only submit these bios after dropping the jbd2 handle. Signed-off-by: Xiaoguang Wang Reviewed-by: Liu Bo Signed-off-by: Joseph Qi Acked-by: Caspar Zhang --- fs/ext4/ext4.h | 12 ++++++++++++ fs/ext4/inode.c | 5 ++++- fs/ext4/page-io.c | 43 ++++++++++++++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 458101f2cada..8040f5831552 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -226,9 +226,21 @@ typedef struct ext4_io_end { struct ext4_io_submit { struct writeback_control *io_wbc; + /* + * When dioread_nolock is enabled, we don't submit bios for unwritten + * extent while holding jbd2 handle, which can avoid jbd2 commit thread + * wait io to complete, for this case, we will link bios cover the + * extent to io_bio using bio->bi_private. + */ struct bio *io_bio; ext4_io_end_t *io_end; sector_t io_next_block; + /* + * If not zero, we have an active bio and can submit this bio or add + * new bh to this bio, if zero, we'll need to allocate a new bio. + */ + int have_active_bio; + int can_submit; }; /* diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 684467c50583..d7cce6f97d57 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2496,6 +2496,7 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd) mpd->io_submit.io_end->handle = handle->h_rsv_handle; handle->h_rsv_handle = NULL; } + mpd->io_submit.can_submit = 0; ext4_set_io_unwritten_flag(inode, mpd->io_submit.io_end); } @@ -2921,7 +2922,9 @@ static int ext4_writepages(struct address_space *mapping, } /* Unlock pages we didn't use */ mpage_release_unused_pages(&mpd, give_up_on_write); - /* Submit prepared bio */ + /* Submit all prepared bio */ + if (!mpd.io_submit.can_submit) + mpd.io_submit.can_submit = 1; ext4_io_submit(&mpd.io_submit); /* diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index db7590178dfc..56a66a227c09 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -346,15 +346,27 @@ static void ext4_end_bio(struct bio *bio) void ext4_io_submit(struct ext4_io_submit *io) { - struct bio *bio = io->io_bio; - - if (bio) { - int io_op_flags = io->io_wbc->sync_mode == WB_SYNC_ALL ? - REQ_SYNC : 0; - io->io_bio->bi_write_hint = io->io_end->inode->i_write_hint; - bio_set_op_attrs(io->io_bio, REQ_OP_WRITE, io_op_flags); - submit_bio(io->io_bio); + struct bio *bio = io->io_bio, *next = NULL; + int io_op_flags = io->io_wbc->sync_mode == WB_SYNC_ALL ? REQ_SYNC : 0; + + if (!io->can_submit) { + /* + * Caller tries to submit this bio, but currently we can not + * submit this bio, we set have_active_bio to zero, then caller + * will allocate a new bio. + */ + io->have_active_bio = 0; + return; } + + for (bio = io->io_bio; bio; bio = next) { + next = bio->bi_private; + bio->bi_write_hint = io->io_end->inode->i_write_hint; + bio_set_op_attrs(bio, REQ_OP_WRITE, io_op_flags); + bio->bi_private = ext4_get_io_end(io->io_end); + submit_bio(bio); + } + io->have_active_bio = 0; io->io_bio = NULL; } @@ -364,6 +376,13 @@ void ext4_io_submit_init(struct ext4_io_submit *io, io->io_wbc = wbc; io->io_bio = NULL; io->io_end = NULL; + /* + * When dioread_nolock is enabled and submit unwritten extents, + * set can_submit to zero, then we'll accumulate bios for this + * extent and submit these bios after drop jdb2 handle. + */ + io->can_submit = 1; + io->have_active_bio = 0; } static int io_submit_init_bio(struct ext4_io_submit *io, @@ -378,8 +397,10 @@ static int io_submit_init_bio(struct ext4_io_submit *io, bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio_set_dev(bio, bh->b_bdev); bio->bi_end_io = ext4_end_bio; - bio->bi_private = ext4_get_io_end(io->io_end); + /* Point to previous bio if there is */ + bio->bi_private = io->io_bio; io->io_bio = bio; + io->have_active_bio = 1; io->io_next_block = bh->b_blocknr; return 0; } @@ -391,11 +412,11 @@ static int io_submit_add_bh(struct ext4_io_submit *io, { int ret; - if (io->io_bio && bh->b_blocknr != io->io_next_block) { + if (io->have_active_bio && bh->b_blocknr != io->io_next_block) { submit_and_retry: ext4_io_submit(io); } - if (io->io_bio == NULL) { + if (!io->have_active_bio) { ret = io_submit_init_bio(io, bh); if (ret) return ret; -- GitLab