All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] btrfs: fix embarrassing bugs in find_next_dirty_byte()
@ 2021-06-05  0:14 Qu Wenruo
  2021-06-07 17:08 ` David Sterba
  0 siblings, 1 reply; 4+ messages in thread
From: Qu Wenruo @ 2021-06-05  0:14 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

There are several bugs in find_next_dirty_byte():

- Wrong right shift
  int nbits = (orig_start - page_offset(page)) >> fs_info->sectorsize;

  This makes nbits to be always 0, thus find_next_dirty_byte() doesn't
  really check any range, but bit by bit check.

  This mask all other bugs in the same function.

- Wrong @first_bit_zero calculation
  The real @first_bit_zero we want should be after @first_bit_set.

All these bit dancing with tons of ASSERT() is really a waste of time.
The only reason I didn't go bitmap operations is they require unsigned
long.

But considering how many bugs there are just in this small function,
bitmap_next_set_region() should be the correct way to go.

Fix all these mess by using unsigned long for the local bitmap, and call
bitmap_next_set_region() to end all these stupid bugs.

Thankfully, this bug can be easily verify by any short fsstress/fsx run.

Please fold this fix into "btrfs: make __extent_writepage_io() only submit dirty range for subpage".

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/extent_io.c | 38 +++++++++-----------------------------
 1 file changed, 9 insertions(+), 29 deletions(-)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index d6a12f7e36d9..77b59ca93419 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -3877,11 +3877,12 @@ static void find_next_dirty_byte(struct btrfs_fs_info *fs_info,
 {
 	struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
 	u64 orig_start = *start;
-	u16 dirty_bitmap;
+	/* Declare as unsigned long so we can use bitmap ops */
+	unsigned long dirty_bitmap;
 	unsigned long flags;
-	int nbits = (orig_start - page_offset(page)) >> fs_info->sectorsize;
-	int first_bit_set;
-	int first_bit_zero;
+	int nbits = (orig_start - page_offset(page)) >> fs_info->sectorsize_bits;
+	int range_start_bit = nbits;
+	int range_end_bit;
 
 	/*
 	 * For regular sector size == page size case, since one page only
@@ -3898,31 +3899,10 @@ static void find_next_dirty_byte(struct btrfs_fs_info *fs_info,
 	dirty_bitmap = subpage->dirty_bitmap;
 	spin_unlock_irqrestore(&subpage->lock, flags);
 
-	/* Set bits lower than @nbits with 0 */
-	dirty_bitmap &= ~((1 << nbits) - 1);
-
-	first_bit_set = ffs(dirty_bitmap);
-	/* No dirty range found */
-	if (first_bit_set == 0) {
-		*start = page_offset(page) + PAGE_SIZE;
-		return;
-	}
-
-	ASSERT(first_bit_set > 0 && first_bit_set <= BTRFS_SUBPAGE_BITMAP_SIZE);
-	*start = page_offset(page) + (first_bit_set - 1) * fs_info->sectorsize;
-
-	/* Set all bits lower than @nbits to 1 for ffz() */
-	dirty_bitmap |= ((1 << nbits) - 1);
-
-	first_bit_zero = ffz(dirty_bitmap);
-	if (first_bit_zero == 0 || first_bit_zero > BTRFS_SUBPAGE_BITMAP_SIZE) {
-		*end = page_offset(page) + PAGE_SIZE;
-		return;
-	}
-	ASSERT(first_bit_zero > 0 &&
-	       first_bit_zero <= BTRFS_SUBPAGE_BITMAP_SIZE);
-	*end = page_offset(page) + first_bit_zero * fs_info->sectorsize;
-	ASSERT(*end > *start);
+	bitmap_next_set_region(&dirty_bitmap, &range_start_bit, &range_end_bit,
+			       BTRFS_SUBPAGE_BITMAP_SIZE);
+	*start = page_offset(page) + range_start_bit * fs_info->sectorsize;
+	*end = page_offset(page) + range_end_bit * fs_info->sectorsize;
 }
 
 /*
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-06-08 14:09 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-05  0:14 [PATCH] btrfs: fix embarrassing bugs in find_next_dirty_byte() Qu Wenruo
2021-06-07 17:08 ` David Sterba
2021-06-08  2:02   ` Qu Wenruo
2021-06-08 14:06     ` David Sterba

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.