linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Christoph Hellwig <hch@lst.de>
To: Chris Mason <clm@fb.com>, Josef Bacik <josef@toxicpanda.com>,
	David Sterba <dsterba@suse.com>
Cc: Matthew Wilcox <willy@infradead.org>,
	linux-btrfs@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: [PATCH 19/23] btrfs: don't redirty pages in compress_file_range
Date: Wed, 28 Jun 2023 17:31:40 +0200	[thread overview]
Message-ID: <20230628153144.22834-20-hch@lst.de> (raw)
In-Reply-To: <20230628153144.22834-1-hch@lst.de>

compress_file_range needs to clear the dirty bit before handing off work
to the compression worker threads to prevent processes coming in through
mmap and changing the file contents while the compression is accessing
the data (See commit 4adaa611020f ("Btrfs: fix race between mmap writes
and compression").

But when compress_file_range decides to not compress the data, it falls
back to submit_uncompressed_range which uses extent_write_locked_range
to write the uncompressed data.  extent_write_locked_range currently
expects all pages to be marked dirty so that it can clear the dirty
bit itself, and thus compress_file_range has to redirty the page range.

Redirtying the page range is rather inefficient and also pointless,
so instead pass a pages_dirty parameter to extent_write_locked_range
and skip the redirty game entirely.

Note that compress_file_range was even redirtying the locked_page twice
given that extent_range_clear_dirty_for_io already redirties all pages
in the range, which must include locked_page if there is one.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/btrfs/extent_io.c | 29 +++++------------------------
 fs/btrfs/extent_io.h |  3 +--
 fs/btrfs/inode.c     | 43 +++++++++----------------------------------
 3 files changed, 15 insertions(+), 60 deletions(-)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 6befffd76e8808..e74153c02d84c7 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -181,22 +181,6 @@ void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end)
 	}
 }
 
-void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end)
-{
-	struct address_space *mapping = inode->i_mapping;
-	unsigned long index = start >> PAGE_SHIFT;
-	unsigned long end_index = end >> PAGE_SHIFT;
-	struct folio *folio;
-
-	while (index <= end_index) {
-		folio = filemap_get_folio(mapping, index);
-		filemap_dirty_folio(mapping, folio);
-		folio_account_redirty(folio);
-		index += folio_nr_pages(folio);
-		folio_put(folio);
-	}
-}
-
 static void process_one_page(struct btrfs_fs_info *fs_info,
 			     struct page *page, struct page *locked_page,
 			     unsigned long page_ops, u64 start, u64 end)
@@ -2150,7 +2134,7 @@ static int extent_write_cache_pages(struct address_space *mapping,
  * locked.
  */
 void extent_write_locked_range(struct inode *inode, u64 start, u64 end,
-			       struct writeback_control *wbc)
+			       struct writeback_control *wbc, bool pages_dirty)
 {
 	bool found_error = false;
 	int ret = 0;
@@ -2176,14 +2160,11 @@ void extent_write_locked_range(struct inode *inode, u64 start, u64 end,
 		int nr = 0;
 
 		page = find_get_page(mapping, cur >> PAGE_SHIFT);
-		/*
-		 * All pages in the range are locked since
-		 * btrfs_run_delalloc_range(), thus there is no way to clear
-		 * the page dirty flag.
-		 */
 		ASSERT(PageLocked(page));
-		ASSERT(PageDirty(page));
-		clear_page_dirty_for_io(page);
+		if (pages_dirty) {
+			ASSERT(PageDirty(page));
+			clear_page_dirty_for_io(page);
+		}
 
 		ret = __extent_writepage_io(BTRFS_I(inode), page, &bio_ctrl,
 					    i_size, &nr);
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 0312022bbf4b7a..2678906e87c506 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -178,7 +178,7 @@ int try_release_extent_buffer(struct page *page);
 
 int btrfs_read_folio(struct file *file, struct folio *folio);
 void extent_write_locked_range(struct inode *inode, u64 start, u64 end,
-			       struct writeback_control *wbc);
+			       struct writeback_control *wbc, bool pages_dirty);
 int extent_writepages(struct address_space *mapping,
 		      struct writeback_control *wbc);
 int btree_write_cache_pages(struct address_space *mapping,
@@ -265,7 +265,6 @@ void set_extent_buffer_dirty(struct extent_buffer *eb);
 void set_extent_buffer_uptodate(struct extent_buffer *eb);
 void clear_extent_buffer_uptodate(struct extent_buffer *eb);
 void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
-void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
 void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
 				  struct page *locked_page,
 				  u32 bits_to_clear, unsigned long page_ops);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8f3a72f3f897a1..556f63e8496ff8 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -848,10 +848,16 @@ static void compress_file_range(struct btrfs_work *work)
 	unsigned int poff;
 	int i;
 	int compress_type = fs_info->compress_type;
-	int redirty = 0;
 
 	inode_should_defrag(inode, start, end, end - start + 1, SZ_16K);
 
+	/*
+	 * We need to call clear_page_dirty_for_io on each page in the range.
+	 * Otherwise applications with the file mmap'd can wander in and change
+	 * the page contents while we are compressing them.
+	 */
+	extent_range_clear_dirty_for_io(&inode->vfs_inode, start, end);
+
 	/*
 	 * We need to save i_size before now because it could change in between
 	 * us evaluating the size and assigning it.  This is because we lock and
@@ -927,22 +933,6 @@ static void compress_file_range(struct btrfs_work *work)
 	else if (inode->prop_compress)
 		compress_type = inode->prop_compress;
 
-	/*
-	 * We need to call clear_page_dirty_for_io on each page in the range.
-	 * Otherwise applications with the file mmap'd can wander in and change
-	 * the page contents while we are compressing them.
-	 *
-	 * If the compression fails for any reason, we set the pages dirty again
-	 * later on.
-	 *
-	 * Note that the remaining part is redirtied, the start pointer has
-	 * moved, the end is the original one.
-	 */
-	if (!redirty) {
-		extent_range_clear_dirty_for_io(&inode->vfs_inode, start, end);
-		redirty = 1;
-	}
-
 	/* Compression level is applied here and only here */
 	ret = btrfs_compress_pages(compress_type |
 				   (fs_info->compress_level << 4),
@@ -1039,21 +1029,6 @@ static void compress_file_range(struct btrfs_work *work)
 	if (!btrfs_test_opt(fs_info, FORCE_COMPRESS) && !inode->prop_compress)
 		inode->flags |= BTRFS_INODE_NOCOMPRESS;
 cleanup_and_bail_uncompressed:
-	/*
-	 * No compression, but we still need to write the pages in the file
-	 * we've been given so far.  redirty the locked page if it corresponds
-	 * to our extent and set things up for the async work queue to run
-	 * cow_file_range to do the normal delalloc dance.
-	 */
-	if (async_chunk->locked_page &&
-	    (page_offset(async_chunk->locked_page) >= start &&
-	     page_offset(async_chunk->locked_page)) <= end) {
-		__set_page_dirty_nobuffers(async_chunk->locked_page);
-		/* unlocked later on in the async handlers */
-	}
-
-	if (redirty)
-		extent_range_redirty_for_io(&inode->vfs_inode, start, end);
 	add_async_extent(async_chunk, start, end - start + 1, 0, NULL, 0,
 			 BTRFS_COMPRESS_NONE);
 free_pages:
@@ -1130,7 +1105,7 @@ static void submit_uncompressed_range(struct btrfs_inode *inode,
 
 	/* All pages will be unlocked, including @locked_page */
 	wbc_attach_fdatawrite_inode(&wbc, &inode->vfs_inode);
-	extent_write_locked_range(&inode->vfs_inode, start, end, &wbc);
+	extent_write_locked_range(&inode->vfs_inode, start, end, &wbc, false);
 	wbc_detach_inode(&wbc);
 }
 
@@ -1755,7 +1730,7 @@ static noinline int run_delalloc_zoned(struct btrfs_inode *inode,
 		}
 		locked_page_done = true;
 		extent_write_locked_range(&inode->vfs_inode, start, done_offset,
-					  wbc);
+					  wbc, true);
 		start = done_offset + 1;
 	}
 
-- 
2.39.2


  parent reply	other threads:[~2023-06-28 15:33 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-28 15:31 btrfs compressed writeback cleanups Christoph Hellwig
2023-06-28 15:31 ` [PATCH 01/23] btrfs: pass a flags argument to cow_file_range Christoph Hellwig
2023-07-04  8:47   ` Johannes Thumshirn
2023-07-20 11:22   ` David Sterba
2023-07-20 13:25     ` Christoph Hellwig
2023-06-28 15:31 ` [PATCH 02/23] btrfs: don't create inline extents in fallback_to_cow Christoph Hellwig
2023-06-28 15:31 ` [PATCH 03/23] btrfs: split page locking out of __process_pages_contig Christoph Hellwig
2023-06-28 15:31 ` [PATCH 04/23] btrfs: remove btrfs_writepage_endio_finish_ordered Christoph Hellwig
2023-07-04  8:50   ` Johannes Thumshirn
2023-06-28 15:31 ` [PATCH 05/23] btrfs: remove end_extent_writepage Christoph Hellwig
2023-06-28 15:31 ` [PATCH 06/23] btrfs: reduce debug spam from submit_compressed_extents Christoph Hellwig
2023-07-04  8:54   ` Johannes Thumshirn
2023-06-28 15:31 ` [PATCH 07/23] btrfs: remove the return value from submit_uncompressed_range Christoph Hellwig
2023-07-04  8:56   ` Johannes Thumshirn
2023-06-28 15:31 ` [PATCH 08/23] btrfs: remove the return value from extent_write_locked_range Christoph Hellwig
2023-07-04  8:56   ` Johannes Thumshirn
2023-06-28 15:31 ` [PATCH 09/23] btrfs: improve the delalloc_to_write calculation in writepage_delalloc Christoph Hellwig
2023-06-28 15:31 ` [PATCH 10/23] btrfs: reduce the number of arguments to btrfs_run_delalloc_range Christoph Hellwig
2023-07-04  9:00   ` Johannes Thumshirn
2023-06-28 15:31 ` [PATCH 11/23] btrfs: clean up the check for uncompressed ranges in submit_one_async_extent Christoph Hellwig
2023-07-04  9:07   ` Johannes Thumshirn
2023-06-28 15:31 ` [PATCH 12/23] btrfs: don't clear async_chunk->inode in async_cow_start Christoph Hellwig
2023-06-28 15:31 ` [PATCH 13/23] btrfs: merge async_cow_start and compress_file_range Christoph Hellwig
2023-07-04  9:09   ` Johannes Thumshirn
2023-06-28 15:31 ` [PATCH 14/23] btrfs: merge submit_compressed_extents and async_cow_submit Christoph Hellwig
2023-06-28 15:31 ` [PATCH 15/23] btrfs: streamline compress_file_range Christoph Hellwig
2023-06-28 15:31 ` [PATCH 16/23] btrfs: further simplify the compress or not logic in compress_file_range Christoph Hellwig
2023-07-14 13:47   ` Josef Bacik
2023-06-28 15:31 ` [PATCH 17/23] btrfs: use a separate label for the incompressible case " Christoph Hellwig
2023-06-28 15:31 ` [PATCH 18/23] btrfs: share the code to free the page array " Christoph Hellwig
2023-06-28 15:31 ` Christoph Hellwig [this message]
2023-07-20 11:41   ` [PATCH 19/23] btrfs: don't redirty pages " David Sterba
2023-07-20 13:26     ` Christoph Hellwig
2023-06-28 15:31 ` [PATCH 20/23] btrfs: refactor the zoned device handling in cow_file_range Christoph Hellwig
2023-06-28 15:31 ` [PATCH 21/23] btrfs: don't redirty locked_page in run_delalloc_zoned Christoph Hellwig
2023-06-28 15:31 ` [PATCH 22/23] btrfs: fix zoned handling in submit_uncompressed_range Christoph Hellwig
2023-06-28 15:31 ` [PATCH 23/23] mm: remove folio_account_redirty Christoph Hellwig
2023-06-28 15:45   ` Matthew Wilcox
2023-07-14 13:49 ` btrfs compressed writeback cleanups Josef Bacik
2023-07-20 11:47 ` David Sterba

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230628153144.22834-20-hch@lst.de \
    --to=hch@lst.de \
    --cc=clm@fb.com \
    --cc=dsterba@suse.com \
    --cc=josef@toxicpanda.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=willy@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).