]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
btrfs: ensure removal of discardable_* in free_bitmap()
authorDennis Zhou <dennis@kernel.org>
Thu, 2 Jan 2020 21:26:45 +0000 (16:26 -0500)
committerDavid Sterba <dsterba@suse.com>
Mon, 20 Jan 2020 15:41:01 +0000 (16:41 +0100)
Most callers of free_bitmap() only call it if bitmap_info->bytes is 0.
However, there are certain cases where we may free the free space cache
via __btrfs_remove_free_space_cache(). This exposes a path where
free_bitmap() is called regardless. This may result in a bad accounting
situation for discardable_bytes and discardable_extents. So, remove the
stats and call btrfs_discard_update_discardable().

Signed-off-by: Dennis Zhou <dennis@kernel.org>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/free-space-cache.c

index 30e0108520400a53eca767e05b68c221d1b3d0ef..0598fd3c6e3f1c97848b4b56308c356fb8002beb 100644 (file)
@@ -1959,6 +1959,18 @@ static void add_new_bitmap(struct btrfs_free_space_ctl *ctl,
 static void free_bitmap(struct btrfs_free_space_ctl *ctl,
                        struct btrfs_free_space *bitmap_info)
 {
+       /*
+        * Normally when this is called, the bitmap is completely empty. However,
+        * if we are blowing up the free space cache for one reason or another
+        * via __btrfs_remove_free_space_cache(), then it may not be freed and
+        * we may leave stats on the table.
+        */
+       if (bitmap_info->bytes && !btrfs_free_space_trimmed(bitmap_info)) {
+               ctl->discardable_extents[BTRFS_STAT_CURR] -=
+                       bitmap_info->bitmap_extents;
+               ctl->discardable_bytes[BTRFS_STAT_CURR] -= bitmap_info->bytes;
+
+       }
        unlink_free_space(ctl, bitmap_info);
        kmem_cache_free(btrfs_free_space_bitmap_cachep, bitmap_info->bitmap);
        kmem_cache_free(btrfs_free_space_cachep, bitmap_info);
@@ -2776,6 +2788,8 @@ void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl)
 {
        spin_lock(&ctl->tree_lock);
        __btrfs_remove_free_space_cache_locked(ctl);
+       if (ctl->private)
+               btrfs_discard_update_discardable(ctl->private, ctl);
        spin_unlock(&ctl->tree_lock);
 }