diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 458101f2cada526c3e9ac36d61003322a4eb6cba..8040f58315527ac630ca2c786fdec138ca423193 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 5af0d9fb875636bba4c5286105746e5199f17010..d437703750f55df925866da2dca18ac1542cfe73 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2505,6 +2505,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); } @@ -2930,7 +2931,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 db7590178dfcf1a4b59ee3c44deaa89a21de8ca6..56a66a227c09eaa1519b4402bf201c958275e557 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;