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_satoru@xxxxxxxxxxxxxx>
Signed-off-by: Wang Xiaoguang <wangxg.fnst@xxxxxxxxxxxxxx>
Signed-off-by: Qu Wenruo <quwenruo@xxxxxxxxxxxxxx>
---
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html