Dedupe has a bug that underflow block_group_cache->delalloc_bytes, makes
it unable to return to 0.
This will cause free space cache for that block group never written to
disk.

And cause the following kernel message at umount:
BTRFS info (device vdc): The free space cache file (1485570048) is
invalid. skip it

Reported-by: Satoru Takeuchi <takeuchi_sat...@jp.fujitsu.com>
Signed-off-by: Wang Xiaoguang <wangxg.f...@cn.fujitsu.com>
Signed-off-by: Qu Wenruo <quwen...@cn.fujitsu.com>
---
 fs/btrfs/extent-tree.c |  8 ++++++--
 fs/btrfs/inode.c       | 11 +++++++++--
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 016d2ec..f6dbef3 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -6256,8 +6256,12 @@ static int btrfs_update_reserved_bytes(struct 
btrfs_block_group_cache *cache,
                cache->reserved -= num_bytes;
                space_info->bytes_reserved -= num_bytes;
 
-               if (delalloc)
-                       cache->delalloc_bytes -= num_bytes;
+               if (delalloc) {
+                       if (WARN_ON(num_bytes > cache->delalloc_bytes))
+                               cache->delalloc_bytes = 0;
+                       else
+                               cache->delalloc_bytes -= num_bytes;
+               }
        }
        spin_unlock(&cache->lock);
        spin_unlock(&space_info->lock);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8a2a76a..5014ece 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3045,7 +3045,10 @@ static void btrfs_release_delalloc_bytes(struct 
btrfs_root *root,
        ASSERT(cache);
 
        spin_lock(&cache->lock);
-       cache->delalloc_bytes -= len;
+       if (WARN_ON(len > cache->delalloc_bytes))
+               cache->delalloc_bytes = 0;
+       else
+               cache->delalloc_bytes -= len;
        spin_unlock(&cache->lock);
 
        btrfs_put_block_group(cache);
@@ -3154,6 +3157,9 @@ static int btrfs_finish_ordered_io(struct 
btrfs_ordered_extent *ordered_extent)
                                                ordered_extent->file_offset +
                                                logical_len);
        } else {
+               /* Must be checked before hash modified*/
+               int hash_hit = btrfs_dedupe_hash_hit(ordered_extent->hash);
+
                BUG_ON(root == root->fs_info->tree_root);
                ret = insert_reserved_file_extent(trans, inode,
                                                ordered_extent->file_offset,
@@ -3163,7 +3169,8 @@ static int btrfs_finish_ordered_io(struct 
btrfs_ordered_extent *ordered_extent)
                                                compress_type, 0, 0,
                                                BTRFS_FILE_EXTENT_REG,
                                                ordered_extent->hash);
-               if (!ret)
+               /* Hash hit case doesn't reserved delalloc bytes */
+               if (!ret && !hash_hit)
                        btrfs_release_delalloc_bytes(root,
                                                     ordered_extent->start,
                                                     ordered_extent->disk_len);
-- 
2.7.3



--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to