--- /dev/null
+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)