]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 14 Jun 2012 22:44:04 +0000 (15:44 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 14 Jun 2012 22:44:04 +0000 (15:44 -0700)
added patches:
hugetlb-fix-resv_map-leak-in-error-path.patch

queue-3.0/hugetlb-fix-resv_map-leak-in-error-path.patch [new file with mode: 0644]
queue-3.0/series

diff --git a/queue-3.0/hugetlb-fix-resv_map-leak-in-error-path.patch b/queue-3.0/hugetlb-fix-resv_map-leak-in-error-path.patch
new file mode 100644 (file)
index 0000000..65bd251
--- /dev/null
@@ -0,0 +1,111 @@
+From c50ac050811d6485616a193eb0f37bfbd191cc89 Mon Sep 17 00:00:00 2001
+From: Dave Hansen <dave@linux.vnet.ibm.com>
+Date: Tue, 29 May 2012 15:06:46 -0700
+Subject: hugetlb: fix resv_map leak in error path
+
+From: Dave Hansen <dave@linux.vnet.ibm.com>
+
+commit c50ac050811d6485616a193eb0f37bfbd191cc89 and
+4523e1458566a0e8ecfaff90f380dd23acc44d27 upstream.
+
+When called for anonymous (non-shared) mappings, hugetlb_reserve_pages()
+does a resv_map_alloc().  It depends on code in hugetlbfs's
+vm_ops->close() to release that allocation.
+
+However, in the mmap() failure path, we do a plain unmap_region() without
+the remove_vma() which actually calls vm_ops->close().
+
+This is a decent fix.  This leak could get reintroduced if new code (say,
+after hugetlb_reserve_pages() in hugetlbfs_file_mmap()) decides to return
+an error.  But, I think it would have to unroll the reservation anyway.
+
+Christoph's test case:
+
+       http://marc.info/?l=linux-mm&m=133728900729735
+
+This patch applies to 3.4 and later.  A version for earlier kernels is at
+https://lkml.org/lkml/2012/5/22/418.
+
+Signed-off-by: Dave Hansen <dave@linux.vnet.ibm.com>
+Acked-by: Mel Gorman <mel@csn.ul.ie>
+Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Reported-by: Christoph Lameter <cl@linux.com>
+Tested-by: Christoph Lameter <cl@linux.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ mm/hugetlb.c |   29 +++++++++++++++++++++++------
+ 1 file changed, 23 insertions(+), 6 deletions(-)
+
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -2060,6 +2060,15 @@ static void hugetlb_vm_op_open(struct vm
+               kref_get(&reservations->refs);
+ }
++static void resv_map_put(struct vm_area_struct *vma)
++{
++      struct resv_map *reservations = vma_resv_map(vma);
++
++      if (!reservations)
++              return;
++      kref_put(&reservations->refs, resv_map_release);
++}
++
+ static void hugetlb_vm_op_close(struct vm_area_struct *vma)
+ {
+       struct hstate *h = hstate_vma(vma);
+@@ -2075,7 +2084,7 @@ static void hugetlb_vm_op_close(struct v
+               reserve = (end - start) -
+                       region_count(&reservations->regions, start, end);
+-              kref_put(&reservations->refs, resv_map_release);
++              resv_map_put(vma);
+               if (reserve) {
+                       hugetlb_acct_memory(h, -reserve);
+@@ -2877,12 +2886,16 @@ int hugetlb_reserve_pages(struct inode *
+               set_vma_resv_flags(vma, HPAGE_RESV_OWNER);
+       }
+-      if (chg < 0)
+-              return chg;
++      if (chg < 0) {
++              ret = chg;
++              goto out_err;
++      }
+       /* There must be enough filesystem quota for the mapping */
+-      if (hugetlb_get_quota(inode->i_mapping, chg))
+-              return -ENOSPC;
++      if (hugetlb_get_quota(inode->i_mapping, chg)) {
++              ret = -ENOSPC;
++              goto out_err;
++      }
+       /*
+        * Check enough hugepages are available for the reservation.
+@@ -2891,7 +2904,7 @@ int hugetlb_reserve_pages(struct inode *
+       ret = hugetlb_acct_memory(h, chg);
+       if (ret < 0) {
+               hugetlb_put_quota(inode->i_mapping, chg);
+-              return ret;
++              goto out_err;
+       }
+       /*
+@@ -2908,6 +2921,10 @@ int hugetlb_reserve_pages(struct inode *
+       if (!vma || vma->vm_flags & VM_MAYSHARE)
+               region_add(&inode->i_mapping->private_list, from, to);
+       return 0;
++out_err:
++      if (vma)
++              resv_map_put(vma);
++      return ret;
+ }
+ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
index 4c92d33248cde20428699514b4d604a4f58f37a9..a3b512ef377a9560764f3277d7a1ffa1143d177f 100644 (file)
@@ -17,3 +17,4 @@ fuse-fix-stat-call-on-32-bit-platforms.patch
 e1000-save-skb-counts-in-tx-to-avoid-cache-misses.patch
 mm-vmalloc.c-change-void-into-explict-vm_struct.patch
 mm-fix-faulty-initialization-in-vmalloc_init.patch
+hugetlb-fix-resv_map-leak-in-error-path.patch