From: Qu Wenruo Date: Mon, 27 Sep 2021 07:22:06 +0000 (+0800) Subject: btrfs: handle page locking in btrfs_page_end_writer_lock with no writers X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=164674a76b25da9c9ea2759eeaa8ef6f1b4ad6c8;p=linux.git btrfs: handle page locking in btrfs_page_end_writer_lock with no writers There are several call sites of extent_clear_unlock_delalloc() which get @locked_page = NULL. So that extent_clear_unlock_delalloc() will try to call process_one_page() to unlock every page even the first page is not locked by btrfs_page_start_writer_lock(). This will trigger an ASSERT() in btrfs_subpage_end_and_test_writer() as previously we require every page passed to btrfs_subpage_end_and_test_writer() to be locked by btrfs_page_start_writer_lock(). But compression path doesn't go that way. Thankfully it's not hard to distinguish page locked by lock_page() and btrfs_page_start_writer_lock(). So do the check in btrfs_subpage_end_and_test_writer() so now it can handle both cases well. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- diff --git a/fs/btrfs/subpage.c b/fs/btrfs/subpage.c index 265b6aa1c662d..29bd8c7a7706b 100644 --- a/fs/btrfs/subpage.c +++ b/fs/btrfs/subpage.c @@ -292,6 +292,16 @@ bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info, btrfs_subpage_assert(fs_info, page, start, len); + /* + * We have call sites passing @lock_page into + * extent_clear_unlock_delalloc() for compression path. + * + * This @locked_page is locked by plain lock_page(), thus its + * subpage::writers is 0. Handle them in a special way. + */ + if (atomic_read(&subpage->writers) == 0) + return true; + ASSERT(atomic_read(&subpage->writers) >= nbits); return atomic_sub_and_test(nbits, &subpage->writers); }