]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 2 Apr 2013 20:04:26 +0000 (13:04 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 2 Apr 2013 20:04:26 +0000 (13:04 -0700)
added patches:
btrfs-fix-space-leak-when-we-fail-to-reserve-metadata-space.patch

queue-3.4/btrfs-fix-space-leak-when-we-fail-to-reserve-metadata-space.patch [new file with mode: 0644]
queue-3.4/series

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 (file)
index 0000000..80e6157
--- /dev/null
@@ -0,0 +1,87 @@
+From f4881bc7a83eff263789dd524b7c269d138d4af5 Mon Sep 17 00:00:00 2001
+From: Josef Bacik <jbacik@fusionio.com>
+Date: Mon, 25 Mar 2013 16:03:35 -0400
+Subject: Btrfs: fix space leak when we fail to reserve metadata space
+
+From: Josef Bacik <jbacik@fusionio.com>
+
+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 <dsterba@suse.cz>
+Signed-off-by: Josef Bacik <jbacik@fusionio.com>
+Signed-off-by: Lingzhu Xiang <lxiang@redhat.com>
+Reviewed-by: CAI Qian <caiqian@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
index c0e6597fc747403ed362db284f49d24749c3f939..cbfbec0e31617cafeb8cf8dc5f6839bb0dc0f237 100644 (file)
@@ -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