From 68ce223bb982ff69b7ab1109083fd2a7448d0bd7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 Apr 2013 13:04:26 -0700 Subject: [PATCH] 3.4-stable patches added patches: btrfs-fix-space-leak-when-we-fail-to-reserve-metadata-space.patch --- ...en-we-fail-to-reserve-metadata-space.patch | 87 +++++++++++++++++++ queue-3.4/series | 1 + 2 files changed, 88 insertions(+) create mode 100644 queue-3.4/btrfs-fix-space-leak-when-we-fail-to-reserve-metadata-space.patch diff --git a/queue-3.4/btrfs-fix-space-leak-when-we-fail-to-reserve-metadata-space.patch b/queue-3.4/btrfs-fix-space-leak-when-we-fail-to-reserve-metadata-space.patch new file mode 100644 index 00000000000..80e61575128 --- /dev/null +++ b/queue-3.4/btrfs-fix-space-leak-when-we-fail-to-reserve-metadata-space.patch @@ -0,0 +1,87 @@ +From f4881bc7a83eff263789dd524b7c269d138d4af5 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Mon, 25 Mar 2013 16:03:35 -0400 +Subject: Btrfs: fix space leak when we fail to reserve metadata space + +From: Josef Bacik + +commit f4881bc7a83eff263789dd524b7c269d138d4af5 upstream. + +Dave reported a warning when running xfstest 275. We have been leaking delalloc +metadata space when our reservations fail. This is because we were improperly +calculating how much space to free for our checksum reservations. The problem +is we would sometimes free up space that had already been freed in another +thread and we would end up with negative usage for the delalloc space. This +patch fixes the problem by calculating how much space the other threads would +have already freed, and then calculate how much space we need to free had we not +done the reservation at all, and then freeing any excess space. This makes +xfstests 275 no longer have leaked space. Thanks + +Reported-by: David Sterba +Signed-off-by: Josef Bacik +Signed-off-by: Lingzhu Xiang +Reviewed-by: CAI Qian +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/extent-tree.c | 47 +++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 41 insertions(+), 6 deletions(-) + +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -4486,14 +4486,49 @@ int btrfs_delalloc_reserve_metadata(stru + * If the inodes csum_bytes is the same as the original + * csum_bytes then we know we haven't raced with any free()ers + * so we can just reduce our inodes csum bytes and carry on. +- * Otherwise we have to do the normal free thing to account for +- * the case that the free side didn't free up its reserve +- * because of this outstanding reservation. + */ +- if (BTRFS_I(inode)->csum_bytes == csum_bytes) ++ if (BTRFS_I(inode)->csum_bytes == csum_bytes) { + calc_csum_metadata_size(inode, num_bytes, 0); +- else +- to_free = calc_csum_metadata_size(inode, num_bytes, 0); ++ } else { ++ u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes; ++ u64 bytes; ++ ++ /* ++ * This is tricky, but first we need to figure out how much we ++ * free'd from any free-ers that occured during this ++ * reservation, so we reset ->csum_bytes to the csum_bytes ++ * before we dropped our lock, and then call the free for the ++ * number of bytes that were freed while we were trying our ++ * reservation. ++ */ ++ bytes = csum_bytes - BTRFS_I(inode)->csum_bytes; ++ BTRFS_I(inode)->csum_bytes = csum_bytes; ++ to_free = calc_csum_metadata_size(inode, bytes, 0); ++ ++ ++ /* ++ * Now we need to see how much we would have freed had we not ++ * been making this reservation and our ->csum_bytes were not ++ * artificially inflated. ++ */ ++ BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes; ++ bytes = csum_bytes - orig_csum_bytes; ++ bytes = calc_csum_metadata_size(inode, bytes, 0); ++ ++ /* ++ * Now reset ->csum_bytes to what it should be. If bytes is ++ * more than to_free then we would have free'd more space had we ++ * not had an artificially high ->csum_bytes, so we need to free ++ * the remainder. If bytes is the same or less then we don't ++ * need to do anything, the other free-ers did the correct ++ * thing. ++ */ ++ BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes; ++ if (bytes > to_free) ++ to_free = bytes - to_free; ++ else ++ to_free = 0; ++ } + spin_unlock(&BTRFS_I(inode)->lock); + if (dropped) + to_free += btrfs_calc_trans_metadata_size(root, dropped); diff --git a/queue-3.4/series b/queue-3.4/series index c0e6597fc74..cbfbec0e316 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -34,3 +34,4 @@ loop-prevent-bdev-freeing-while-device-in-use.patch arm-cns3xxx-fix-mapping-of-private-memory-region.patch nfsd4-reject-negative-acl-lengths.patch drm-i915-don-t-clobber-crtc-fb-when-queue_flip-fails.patch +btrfs-fix-space-leak-when-we-fail-to-reserve-metadata-space.patch -- 2.47.3