[PATCH v8 27/27] btrfs: dedupe: Fix a space cache delalloc bytes underflow bug

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux