On 22/11/30 05:35PM, Jan Kara wrote: > When we are writing back page but we cannot for some reason write all > its buffers (e.g. because we cannot allocate blocks in current context) we > have to keep TOWRITE tag set in the mapping as otherwise racing > WB_SYNC_ALL writeback that could write these buffers can skip the page > and result in data loss. We will need this logic for writeback during > transaction commit so move the logic from ext4_writepage() to > ext4_bio_write_page(). Nice explaination. Moving set_page_writeback() and set_page_writeback_keepwrite() to after identifying any buffers needs to be written back or not is also sweet. This avoid unnecessary calling of end_page_writeback(). The patch looks good to me. Please feel free to add: Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@xxxxxxxxx> > > Signed-off-by: Jan Kara <jack@xxxxxxx> > --- > fs/ext4/ext4.h | 3 +-- > fs/ext4/inode.c | 6 ++---- > fs/ext4/page-io.c | 36 +++++++++++++++++++++--------------- > 3 files changed, 24 insertions(+), 21 deletions(-) > > diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h > index 8d5453852f98..1b3bffc04fd0 100644 > --- a/fs/ext4/ext4.h > +++ b/fs/ext4/ext4.h > @@ -3756,8 +3756,7 @@ extern void ext4_end_io_rsv_work(struct work_struct *work); > extern void ext4_io_submit(struct ext4_io_submit *io); > extern int ext4_bio_write_page(struct ext4_io_submit *io, > struct page *page, > - int len, > - bool keep_towrite); > + int len); > extern struct ext4_io_end_vec *ext4_alloc_io_end_vec(ext4_io_end_t *io_end); > extern struct ext4_io_end_vec *ext4_last_io_end_vec(ext4_io_end_t *io_end); > > diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c > index 2b5ef1b64249..43eb175d0c1c 100644 > --- a/fs/ext4/inode.c > +++ b/fs/ext4/inode.c > @@ -2009,7 +2009,6 @@ static int ext4_writepage(struct page *page, > struct buffer_head *page_bufs = NULL; > struct inode *inode = page->mapping->host; > struct ext4_io_submit io_submit; > - bool keep_towrite = false; > > if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) { > folio_invalidate(folio, 0, folio_size(folio)); > @@ -2067,7 +2066,6 @@ static int ext4_writepage(struct page *page, > unlock_page(page); > return 0; > } > - keep_towrite = true; > } > > if (PageChecked(page) && ext4_should_journal_data(inode)) > @@ -2084,7 +2082,7 @@ static int ext4_writepage(struct page *page, > unlock_page(page); > return -ENOMEM; > } > - ret = ext4_bio_write_page(&io_submit, page, len, keep_towrite); > + ret = ext4_bio_write_page(&io_submit, page, len); > ext4_io_submit(&io_submit); > /* Drop io_end reference we got from init */ > ext4_put_io_end_defer(io_submit.io_end); > @@ -2118,7 +2116,7 @@ static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page) > len = size & ~PAGE_MASK; > else > len = PAGE_SIZE; > - err = ext4_bio_write_page(&mpd->io_submit, page, len, false); > + err = ext4_bio_write_page(&mpd->io_submit, page, len); > if (!err) > mpd->wbc->nr_to_write--; > mpd->first_page++; > diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c > index 4e68ace86f11..4f9ecacd10aa 100644 > --- a/fs/ext4/page-io.c > +++ b/fs/ext4/page-io.c > @@ -430,8 +430,7 @@ static void io_submit_add_bh(struct ext4_io_submit *io, > > int ext4_bio_write_page(struct ext4_io_submit *io, > struct page *page, > - int len, > - bool keep_towrite) > + int len) > { > struct page *bounce_page = NULL; > struct inode *inode = page->mapping->host; > @@ -441,14 +440,11 @@ int ext4_bio_write_page(struct ext4_io_submit *io, > int nr_submitted = 0; > int nr_to_submit = 0; > struct writeback_control *wbc = io->io_wbc; > + bool keep_towrite = false; > > BUG_ON(!PageLocked(page)); > BUG_ON(PageWriteback(page)); > > - if (keep_towrite) > - set_page_writeback_keepwrite(page); > - else > - set_page_writeback(page); > ClearPageError(page); > > /* > @@ -483,12 +479,17 @@ int ext4_bio_write_page(struct ext4_io_submit *io, > if (!buffer_mapped(bh)) > clear_buffer_dirty(bh); > /* > - * Keeping dirty some buffer we cannot write? Make > - * sure to redirty the page. This happens e.g. when > - * doing writeout for transaction commit. > + * Keeping dirty some buffer we cannot write? Make sure > + * to redirty the page and keep TOWRITE tag so that > + * racing WB_SYNC_ALL writeback does not skip the page. > + * This happens e.g. when doing writeout for > + * transaction commit. > */ > - if (buffer_dirty(bh) && !PageDirty(page)) > - redirty_page_for_writepage(wbc, page); > + if (buffer_dirty(bh)) { > + if (!PageDirty(page)) > + redirty_page_for_writepage(wbc, page); > + keep_towrite = true; > + } > if (io->io_bio) > ext4_io_submit(io); > continue; > @@ -500,6 +501,10 @@ int ext4_bio_write_page(struct ext4_io_submit *io, > nr_to_submit++; > } while ((bh = bh->b_this_page) != head); > > + /* Nothing to submit? Just unlock the page... */ > + if (!nr_to_submit) > + goto unlock; > + > bh = head = page_buffers(page); > > /* > @@ -550,6 +555,11 @@ int ext4_bio_write_page(struct ext4_io_submit *io, > } > } > > + if (keep_towrite) > + set_page_writeback_keepwrite(page); > + else > + set_page_writeback(page); > + > /* Now submit buffers to write */ > do { > if (!buffer_async_write(bh)) > @@ -558,11 +568,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, > bounce_page ? bounce_page : page, bh); > nr_submitted++; > } while ((bh = bh->b_this_page) != head); > - > unlock: > unlock_page(page); > - /* Nothing submitted - we have to end page writeback */ > - if (!nr_submitted) > - end_page_writeback(page); > return ret; > } > -- > 2.35.3 >