diff mbox series

[2/9] ext4: Move keep_towrite handling to ext4_bio_write_page()

Message ID 20221130163608.29034-2-jack@suse.cz
State Superseded
Headers show
Series ext4: Stop using ext4_writepage() for writeout of ordered data | expand

Commit Message

Jan Kara Nov. 30, 2022, 4:35 p.m. UTC
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().

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/ext4/ext4.h    |  3 +--
 fs/ext4/inode.c   |  6 ++----
 fs/ext4/page-io.c | 36 +++++++++++++++++++++---------------
 3 files changed, 24 insertions(+), 21 deletions(-)

Comments

Ritesh Harjani (IBM) Dec. 1, 2022, 9:13 a.m. UTC | #1
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@gmail.com>



>
> Signed-off-by: Jan Kara <jack@suse.cz>
> ---
>  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
>
diff mbox series

Patch

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;
 }