Patch "btrfs: don't clear uptodate on write errors" has been added to the 6.5-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    btrfs: don't clear uptodate on write errors

to the 6.5-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     btrfs-don-t-clear-uptodate-on-write-errors.patch
and it can be found in the queue-6.5 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 4c332287a5cd2f41bffe3f092df54326d02a0a02
Author: Josef Bacik <josef@xxxxxxxxxxxxxx>
Date:   Fri Sep 8 15:31:39 2023 -0400

    btrfs: don't clear uptodate on write errors
    
    [ Upstream commit b595d25996329427b2c09d4b90395a165fb3ef8e ]
    
    We have been consistently seeing hangs with generic/648 in our subpage
    GitHub CI setup.  This is a classic deadlock, we are calling
    btrfs_read_folio() on a folio, which requires holding the folio lock on
    the folio, and then finding a ordered extent that overlaps that range
    and calling btrfs_start_ordered_extent(), which then tries to write out
    the dirty page, which requires taking the folio lock and then we
    deadlock.
    
    The hang happens because we're writing to range [1271750656, 1271767040),
    page index [77621, 77622], and page 77621 is !Uptodate.  It is also Dirty,
    so we call btrfs_read_folio() for 77621 and which does
    btrfs_lock_and_flush_ordered_range() for that range, and we find an ordered
    extent which is [1271644160, 1271746560), page index [77615, 77621].
    The page indexes overlap, but the actual bytes don't overlap.  We're
    holding the page lock for 77621, then call
    btrfs_lock_and_flush_ordered_range() which tries to flush the dirty
    page, and tries to lock 77621 again and then we deadlock.
    
    The byte ranges do not overlap, but with subpage support if we clear
    uptodate on any portion of the page we mark the entire thing as not
    uptodate.
    
    We have been clearing page uptodate on write errors, but no other file
    system does this, and is in fact incorrect.  This doesn't hurt us in the
    !subpage case because we can't end up with overlapped ranges that don't
    also overlap on the page.
    
    Fix this by not clearing uptodate when we have a write error.  The only
    thing we should be doing in this case is setting the mapping error and
    carrying on.  This makes it so we would no longer call
    btrfs_read_folio() on the page as it's uptodate and eliminates the
    deadlock.
    
    With this patch we're now able to make it through a full fstests run on
    our subpage blocksize VMs.
    
    Note for stable backports: this probably goes beyond 6.1 but the code
    has been cleaned up and clearing the uptodate bit must be verified on
    each version independently.
    
    CC: stable@xxxxxxxxxxxxxxx # 6.1+
    Reviewed-by: Qu Wenruo <wqu@xxxxxxxx>
    Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
    Signed-off-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 009c322c5418d..d8461c9aa2445 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -533,10 +533,8 @@ static void end_bio_extent_writepage(struct btrfs_bio *bbio)
 				   bvec->bv_offset, bvec->bv_len);
 
 		btrfs_finish_ordered_extent(bbio->ordered, page, start, len, !error);
-		if (error) {
-			btrfs_page_clear_uptodate(fs_info, page, start, len);
+		if (error)
 			mapping_set_error(page->mapping, error);
-		}
 		btrfs_page_clear_writeback(fs_info, page, start, len);
 	}
 
@@ -1508,8 +1506,6 @@ static int __extent_writepage(struct page *page, struct btrfs_bio_ctrl *bio_ctrl
 	if (ret) {
 		btrfs_mark_ordered_io_finished(BTRFS_I(inode), page, page_start,
 					       PAGE_SIZE, !ret);
-		btrfs_page_clear_uptodate(btrfs_sb(inode->i_sb), page,
-					  page_start, PAGE_SIZE);
 		mapping_set_error(page->mapping, ret);
 	}
 	unlock_page(page);
@@ -1676,8 +1672,6 @@ static void extent_buffer_write_end_io(struct btrfs_bio *bbio)
 		struct page *page = bvec->bv_page;
 		u32 len = bvec->bv_len;
 
-		if (!uptodate)
-			btrfs_page_clear_uptodate(fs_info, page, start, len);
 		btrfs_page_clear_writeback(fs_info, page, start, len);
 		bio_offset += len;
 	}
@@ -2256,7 +2250,6 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end,
 		if (ret) {
 			btrfs_mark_ordered_io_finished(BTRFS_I(inode), page,
 						       cur, cur_len, !ret);
-			btrfs_page_clear_uptodate(fs_info, page, cur, cur_len);
 			mapping_set_error(page->mapping, ret);
 		}
 		btrfs_page_unlock_writer(fs_info, page, cur, cur_len);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index b126394ca3dde..0f4498dfa30c9 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1162,9 +1162,6 @@ static int submit_uncompressed_range(struct btrfs_inode *inode,
 			btrfs_mark_ordered_io_finished(inode, locked_page,
 						       page_start, PAGE_SIZE,
 						       !ret);
-			btrfs_page_clear_uptodate(inode->root->fs_info,
-						  locked_page, page_start,
-						  PAGE_SIZE);
 			mapping_set_error(locked_page->mapping, ret);
 			unlock_page(locked_page);
 		}
@@ -2951,7 +2948,6 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
 		mapping_set_error(page->mapping, ret);
 		btrfs_mark_ordered_io_finished(inode, page, page_start,
 					       PAGE_SIZE, !ret);
-		btrfs_page_clear_uptodate(fs_info, page, page_start, PAGE_SIZE);
 		clear_page_dirty_for_io(page);
 	}
 	btrfs_page_clear_checked(fs_info, page, page_start, PAGE_SIZE);



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux