* [PATCH] hugetlb: fix resv_map leak in error path
@ 2012-05-21 20:28 Dave Hansen
2012-05-21 22:01 ` KOSAKI Motohiro
2012-05-22 20:45 ` Andrew Morton
0 siblings, 2 replies; 6+ messages in thread
From: Dave Hansen @ 2012-05-21 20:28 UTC (permalink / raw)
To: cl
Cc: linux-kernel, linux-mm, aarcange, kosaki.motohiro, hughd,
rientjes, adobriyan, akpm, mel, Dave Hansen
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.
This hasn't been extensively tested. Pretty much compile and
boot tested along with Christoph's test case:
http://marc.info/?l=linux-mm&m=133728900729735
Signed-off-by: Dave Hansen <dave@linux.vnet.ibm.com>
Acked-by: Mel Gorman <mel@csn.ul.ie>
ecked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Reported/tested-by: Christoph Lameter <cl@linux.com>
---
linux-2.6.git-dave/mm/hugetlb.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff -puN mm/hugetlb.c~hugetlb-fix-leak mm/hugetlb.c
--- linux-2.6.git/mm/hugetlb.c~hugetlb-fix-leak 2012-05-21 13:24:38.369857759 -0700
+++ linux-2.6.git-dave/mm/hugetlb.c 2012-05-21 13:24:38.377857849 -0700
@@ -2157,6 +2157,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);
@@ -2173,7 +2182,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);
@@ -2990,12 +2999,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 pages in the subpool for the mapping */
- if (hugepage_subpool_get_pages(spool, chg))
- return -ENOSPC;
+ if (hugepage_subpool_get_pages(spool, chg)) {
+ ret = -ENOSPC;
+ goto out_err;
+ }
/*
* Check enough hugepages are available for the reservation.
@@ -3004,7 +3017,7 @@ int hugetlb_reserve_pages(struct inode *
ret = hugetlb_acct_memory(h, chg);
if (ret < 0) {
hugepage_subpool_put_pages(spool, chg);
- return ret;
+ goto out_err;
}
/*
@@ -3021,6 +3034,9 @@ 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:
+ resv_map_put(vma);
+ return ret;
}
void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
diff -puN Documentation/stable_kernel_rules.txt~hugetlb-fix-leak Documentation/stable_kernel_rules.txt
_
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH] hugetlb: fix resv_map leak in error path 2012-05-21 20:28 [PATCH] hugetlb: fix resv_map leak in error path Dave Hansen @ 2012-05-21 22:01 ` KOSAKI Motohiro 2012-05-22 20:45 ` Andrew Morton 1 sibling, 0 replies; 6+ messages in thread From: KOSAKI Motohiro @ 2012-05-21 22:01 UTC (permalink / raw) To: dave Cc: cl, linux-kernel, linux-mm, aarcange, kosaki.motohiro, hughd, rientjes, adobriyan, akpm, mel On 5/21/2012 4:28 PM, Dave Hansen wrote: > 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. > > This hasn't been extensively tested. Pretty much compile and > boot tested along with Christoph's test case: > > http://marc.info/?l=linux-mm&m=133728900729735 > > Signed-off-by: Dave Hansen <dave@linux.vnet.ibm.com> > Acked-by: Mel Gorman <mel@csn.ul.ie> > ecked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> typo. ;-) > Reported/tested-by: Christoph Lameter <cl@linux.com> ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] hugetlb: fix resv_map leak in error path 2012-05-21 20:28 [PATCH] hugetlb: fix resv_map leak in error path Dave Hansen 2012-05-21 22:01 ` KOSAKI Motohiro @ 2012-05-22 20:45 ` Andrew Morton 2012-05-22 20:59 ` Dave Hansen 2012-05-22 21:05 ` Christoph Lameter 1 sibling, 2 replies; 6+ messages in thread From: Andrew Morton @ 2012-05-22 20:45 UTC (permalink / raw) To: Dave Hansen Cc: cl, linux-kernel, linux-mm, aarcange, kosaki.motohiro, hughd, rientjes, adobriyan, mel On Mon, 21 May 2012 13:28:14 -0700 Dave Hansen <dave@linux.vnet.ibm.com> wrote: > 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. How far back does this bug go? The patch applies to 3.4 but gets rejects in 3.3 and earlier. > This hasn't been extensively tested. Pretty much compile and > boot tested along with Christoph's test case: > > http://marc.info/?l=linux-mm&m=133728900729735 That isn't my favoritest ever changelog text :( ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] hugetlb: fix resv_map leak in error path 2012-05-22 20:45 ` Andrew Morton @ 2012-05-22 20:59 ` Dave Hansen 2012-05-22 21:05 ` Christoph Lameter 1 sibling, 0 replies; 6+ messages in thread From: Dave Hansen @ 2012-05-22 20:59 UTC (permalink / raw) To: Andrew Morton Cc: cl, linux-kernel, linux-mm, aarcange, kosaki.motohiro, hughd, rientjes, adobriyan, mel On 05/22/2012 01:45 PM, Andrew Morton wrote: > On Mon, 21 May 2012 13:28:14 -0700 > Dave Hansen <dave@linux.vnet.ibm.com> wrote: > >> 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. > > How far back does this bug go? The patch applies to 3.4 but gets > rejects in 3.3 and earlier. commit 17c9d12e126cb0de8d535dc1908c4819d712bc68 Date: Wed Feb 11 16:34:16 2009 +0000 So, ~2.6.30. I don't think it existed before that. The code was there, but the ordering made it OK. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] hugetlb: fix resv_map leak in error path 2012-05-22 20:45 ` Andrew Morton 2012-05-22 20:59 ` Dave Hansen @ 2012-05-22 21:05 ` Christoph Lameter 2012-05-22 21:28 ` Andrew Morton 1 sibling, 1 reply; 6+ messages in thread From: Christoph Lameter @ 2012-05-22 21:05 UTC (permalink / raw) To: Andrew Morton Cc: Dave Hansen, linux-kernel, linux-mm, aarcange, kosaki.motohiro, hughd, rientjes, adobriyan, mel On Tue, 22 May 2012, Andrew Morton wrote: > On Mon, 21 May 2012 13:28:14 -0700 > Dave Hansen <dave@linux.vnet.ibm.com> wrote: > > > 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. > > How far back does this bug go? The patch applies to 3.4 but gets > rejects in 3.3 and earlier. The earliest that I have seen it on was 2.6.32. I have rediffed the patch against 2.6.32 and 3.2.0. ---- >From dave@linux.vnet.ibm.com Fri May 18 13:50:17 2012 Date: Fri, 18 May 2012 11:46:30 -0700 From: Dave Hansen <dave@linux.vnet.ibm.com> To: cl@linux.com Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org, aarcange@redhat.com, kosaki.motohiro@jp.fujitsu.com, hughd@google.com, rientjes@google.com, adobriyan@gmail.com, akpm@linux-foundation.org, mel@csn.ul.ie, Dave Hansen <dave@linux.vnet.ibm.com> Subject: [RFC][PATCH] hugetlb: fix resv_map leak in error path 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. This hasn't been extensively tested. Pretty much compile and boot tested along with Christoph's test case. Comments? Signed-off-by: Dave Hansen <dave@linux.vnet.ibm.com> --- mm/hugetlb.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) Index: linux-3.2.0/mm/hugetlb.c =================================================================== --- linux-3.2.0.orig/mm/hugetlb.c 2012-01-04 17:55:44.000000000 -0600 +++ linux-3.2.0/mm/hugetlb.c 2012-05-22 03:32:37.760054550 -0500 @@ -2068,6 +2068,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); @@ -2083,7 +2092,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); @@ -2883,12 +2892,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. @@ -2897,7 +2910,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; } /* @@ -2914,6 +2927,9 @@ 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: + resv_map_put(vma); + return ret; } void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] hugetlb: fix resv_map leak in error path 2012-05-22 21:05 ` Christoph Lameter @ 2012-05-22 21:28 ` Andrew Morton 0 siblings, 0 replies; 6+ messages in thread From: Andrew Morton @ 2012-05-22 21:28 UTC (permalink / raw) To: Christoph Lameter Cc: Dave Hansen, linux-kernel, linux-mm, aarcange, kosaki.motohiro, hughd, rientjes, adobriyan, mel, stable On Tue, 22 May 2012 16:05:02 -0500 (CDT) Christoph Lameter <cl@linux.com> wrote: > > How far back does this bug go? The patch applies to 3.4 but gets > > rejects in 3.3 and earlier. > > The earliest that I have seen it on was 2.6.32. I have rediffed the patch > against 2.6.32 and 3.2.0. Great, thanks. I did : From: Dave Hansen <dave@linux.vnet.ibm.com> : Subject: hugetlb: fix resv_map leak in error path : : 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> : Cc: <stable@vger.kernel.org> [2.6.32+] ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-05-22 21:28 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-05-21 20:28 [PATCH] hugetlb: fix resv_map leak in error path Dave Hansen 2012-05-21 22:01 ` KOSAKI Motohiro 2012-05-22 20:45 ` Andrew Morton 2012-05-22 20:59 ` Dave Hansen 2012-05-22 21:05 ` Christoph Lameter 2012-05-22 21:28 ` Andrew Morton
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox