aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/reada.c
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2020-10-12 11:55:25 +0100
committerDavid Sterba <dsterba@suse.com>2020-12-08 15:53:38 +0100
commita57ad681f12e1ec80365fc4693e12e979159b9d0 (patch)
tree501d29a935ae49d8d121546dd2ae32330ffa5f4a /fs/btrfs/reada.c
parentbtrfs: set EXTENT_NORESERVE bits side btrfs_dirty_pages() (diff)
downloadlinux-dev-a57ad681f12e1ec80365fc4693e12e979159b9d0.tar.xz
linux-dev-a57ad681f12e1ec80365fc4693e12e979159b9d0.zip
btrfs: assert we are holding the reada_lock when releasing a readahead zone
When we drop the last reference of a zone, we end up releasing it through the callback reada_zone_release(), which deletes the zone from a device's reada_zones radix tree. This tree is protected by the global readahead lock at fs_info->reada_lock. Currently all places that are sure that they are dropping the last reference on a zone, are calling kref_put() in a critical section delimited by this lock, while all other places that are sure they are not dropping the last reference, do not bother calling kref_put() while holding that lock. When working on the previous fix for hangs and use-after-frees in the readahead code, my initial attempts were different and I actually ended up having reada_zone_release() called when not holding the lock, which resulted in weird and unexpected problems. So just add an assertion there to detect such problem more quickly and make the dependency more obvious. Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/reada.c')
-rw-r--r--fs/btrfs/reada.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c
index d9a166eb344e..6e33cb755fa5 100644
--- a/fs/btrfs/reada.c
+++ b/fs/btrfs/reada.c
@@ -531,6 +531,8 @@ static void reada_zone_release(struct kref *kref)
{
struct reada_zone *zone = container_of(kref, struct reada_zone, refcnt);
+ lockdep_assert_held(&zone->device->fs_info->reada_lock);
+
radix_tree_delete(&zone->device->reada_zones,
zone->end >> PAGE_SHIFT);