[PATCH] tmpfs: fix shared mempolicy leak

2012-12-05 Thread Hugh Dickins
From: Mel Gorman 

This fixes a regression in 3.7-rc, which has since gone into stable.

Commit 00442ad04a5e ("mempolicy: fix a memory corruption by refcount
imbalance in alloc_pages_vma()") changed get_vma_policy() to raise the
refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
on expecting alloc_page_vma() to drop the refcount it had acquired.
This deserves a rework: but for now fix the leak in shmem_alloc_page().

Hugh: shmem_swapin() did not need a fix, but surely it's clearer to use
the same refcounting there as in shmem_alloc_page(), delete its onstack
mempolicy, and the strange mpol_cond_copy() and __mpol_cond_copy() -
those were invented to let swapin_readahead() make an unknown number of
calls to alloc_pages_vma() with one mempolicy; but since 00442ad04a5e,
alloc_pages_vma() has kept refcount in balance, so now no problem.

Reported-and-tested-by: Tommi Rantala 
Signed-off-by: Mel Gorman 
Signed-off-by: Hugh Dickins 
Cc: sta...@vger.kernel.org
---

 include/linux/mempolicy.h |   16 
 mm/mempolicy.c|   22 --
 mm/shmem.c|   26 --
 3 files changed, 16 insertions(+), 48 deletions(-)

--- 3.7-rc8/include/linux/mempolicy.h   2012-10-14 16:16:57.637308925 -0700
+++ linux/include/linux/mempolicy.h 2012-12-04 22:38:21.812178829 -0800
@@ -82,16 +82,6 @@ static inline void mpol_cond_put(struct
__mpol_put(pol);
 }
 
-extern struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
- struct mempolicy *frompol);
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *tompol,
-   struct mempolicy *frompol)
-{
-   if (!frompol)
-   return frompol;
-   return __mpol_cond_copy(tompol, frompol);
-}
-
 extern struct mempolicy *__mpol_dup(struct mempolicy *pol);
 static inline struct mempolicy *mpol_dup(struct mempolicy *pol)
 {
@@ -215,12 +205,6 @@ static inline void mpol_cond_put(struct
 {
 }
 
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *to,
-   struct mempolicy *from)
-{
-   return from;
-}
-
 static inline void mpol_get(struct mempolicy *pol)
 {
 }
--- 3078/mm/mempolicy.c 2012-10-20 20:56:24.675917367 -0700
+++ 3078X/mm/mempolicy.c2012-12-04 22:33:31.516171929 -0800
@@ -2037,28 +2037,6 @@ struct mempolicy *__mpol_dup(struct memp
return new;
 }
 
-/*
- * If *frompol needs [has] an extra ref, copy *frompol to *tompol ,
- * eliminate the * MPOL_F_* flags that require conditional ref and
- * [NOTE!!!] drop the extra ref.  Not safe to reference *frompol directly
- * after return.  Use the returned value.
- *
- * Allows use of a mempolicy for, e.g., multiple allocations with a single
- * policy lookup, even if the policy needs/has extra ref on lookup.
- * shmem_readahead needs this.
- */
-struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
-   struct mempolicy *frompol)
-{
-   if (!mpol_needs_cond_ref(frompol))
-   return frompol;
-
-   *tompol = *frompol;
-   tompol->flags &= ~MPOL_F_SHARED;/* copy doesn't need unref */
-   __mpol_put(frompol);
-   return tompol;
-}
-
 /* Slow path of a mempolicy comparison */
 bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
 {
--- 3078/mm/shmem.c 2012-11-16 19:26:56.388459961 -0800
+++ 3078X/mm/shmem.c2012-12-04 22:32:35.328170594 -0800
@@ -910,25 +910,29 @@ static struct mempolicy *shmem_get_sbmpo
 static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
 {
-   struct mempolicy mpol, *spol;
struct vm_area_struct pvma;
-
-   spol = mpol_cond_copy(,
-   mpol_shared_policy_lookup(>policy, index));
+   struct page *page;
 
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
/* Bias interleave by inode number to distribute better across nodes */
pvma.vm_pgoff = index + info->vfs_inode.i_ino;
pvma.vm_ops = NULL;
-   pvma.vm_policy = spol;
-   return swapin_readahead(swap, gfp, , 0);
+   pvma.vm_policy = mpol_shared_policy_lookup(>policy, index);
+
+   page = swapin_readahead(swap, gfp, , 0);
+
+   /* Drop reference taken by mpol_shared_policy_lookup() */
+   mpol_cond_put(pvma.vm_policy);
+
+   return page;
 }
 
 static struct page *shmem_alloc_page(gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
 {
struct vm_area_struct pvma;
+   struct page *page;
 
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
@@ -937,10 +941,12 @@ static struct page *shmem_alloc_page(gfp
pvma.vm_ops = NULL;
pvma.vm_policy = mpol_shared_policy_lookup(>policy, index);
 
-   

Re: [PATCH] tmpfs: fix shared mempolicy leak

2012-12-05 Thread Hugh Dickins
On Wed, 5 Dec 2012, Tommi Rantala wrote:
> 2012/12/5 Mel Gorman :
> > On Tue, Dec 04, 2012 at 11:24:30PM -0800, Hugh Dickins wrote:
> >> From: Mel Gorman 
> >>
> >> Commit 00442ad04a5e ("mempolicy: fix a memory corruption by refcount
> >> imbalance in alloc_pages_vma()") changed get_vma_policy() to raise the
> >> refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
> >> on expecting alloc_page_vma() to drop the refcount it had acquired.
> >> This deserves a rework: but for now fix the leak in shmem_alloc_page().
> >
> > Thanks Hugh for turning gibber into a patch!
> >
> > Signed-off-by: Mel Gorman 
> >
> > Tommi, just in case, can you confirm this fixes the problem for you please?
> 
> Confirmed! No more complaints from kmemleak.

Great, thanks.  I'll update the tags and send straight to Linus now.

Hugh
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] tmpfs: fix shared mempolicy leak

2012-12-05 Thread Tommi Rantala
2012/12/5 Mel Gorman :
> On Tue, Dec 04, 2012 at 11:24:30PM -0800, Hugh Dickins wrote:
>> From: Mel Gorman 
>>
>> Commit 00442ad04a5e ("mempolicy: fix a memory corruption by refcount
>> imbalance in alloc_pages_vma()") changed get_vma_policy() to raise the
>> refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
>> on expecting alloc_page_vma() to drop the refcount it had acquired.
>> This deserves a rework: but for now fix the leak in shmem_alloc_page().
>
> Thanks Hugh for turning gibber into a patch!
>
> Signed-off-by: Mel Gorman 
>
> Tommi, just in case, can you confirm this fixes the problem for you please?

Confirmed! No more complaints from kmemleak.

Thanks,
Tommi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] tmpfs: fix shared mempolicy leak

2012-12-05 Thread Mel Gorman
On Tue, Dec 04, 2012 at 11:24:30PM -0800, Hugh Dickins wrote:
> From: Mel Gorman 
> 
> Commit 00442ad04a5e ("mempolicy: fix a memory corruption by refcount
> imbalance in alloc_pages_vma()") changed get_vma_policy() to raise the
> refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
> on expecting alloc_page_vma() to drop the refcount it had acquired.
> This deserves a rework: but for now fix the leak in shmem_alloc_page().
> 
> Hugh: shmem_swapin() did not need a fix, but surely it's clearer to use
> the same refcounting there as in shmem_alloc_page(), delete its onstack
> mempolicy, and the strange mpol_cond_copy() and __mpol_cond_copy() -
> those were invented to let swapin_readahead() make an unknown number of
> calls to alloc_pages_vma() with one mempolicy; but since 00442ad04a5e,
> alloc_pages_vma() has kept refcount in balance, so now no problem.
> 

Agreed. Anything that reduces the complexity of the mempolicy ref counting
is worthwhile even if it's only by a small bit.

> Reported-by: Tommi Rantala 
> Awaiting-signed-off-by: Mel Gorman 
> Signed-off-by: Hugh Dickins 
> Cc: sta...@vger.kernel.org

Thanks Hugh for turning gibber into a patch!

Signed-off-by: Mel Gorman 

Tommi, just in case, can you confirm this fixes the problem for you please?

-- 
Mel Gorman
SUSE Labs
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] tmpfs: fix shared mempolicy leak

2012-12-05 Thread Mel Gorman
On Tue, Dec 04, 2012 at 11:24:30PM -0800, Hugh Dickins wrote:
 From: Mel Gorman mgor...@suse.de
 
 Commit 00442ad04a5e (mempolicy: fix a memory corruption by refcount
 imbalance in alloc_pages_vma()) changed get_vma_policy() to raise the
 refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
 on expecting alloc_page_vma() to drop the refcount it had acquired.
 This deserves a rework: but for now fix the leak in shmem_alloc_page().
 
 Hugh: shmem_swapin() did not need a fix, but surely it's clearer to use
 the same refcounting there as in shmem_alloc_page(), delete its onstack
 mempolicy, and the strange mpol_cond_copy() and __mpol_cond_copy() -
 those were invented to let swapin_readahead() make an unknown number of
 calls to alloc_pages_vma() with one mempolicy; but since 00442ad04a5e,
 alloc_pages_vma() has kept refcount in balance, so now no problem.
 

Agreed. Anything that reduces the complexity of the mempolicy ref counting
is worthwhile even if it's only by a small bit.

 Reported-by: Tommi Rantala tt.rant...@gmail.com
 Awaiting-signed-off-by: Mel Gorman mgor...@suse.de
 Signed-off-by: Hugh Dickins hu...@google.com
 Cc: sta...@vger.kernel.org

Thanks Hugh for turning gibber into a patch!

Signed-off-by: Mel Gorman mgor...@suse.de

Tommi, just in case, can you confirm this fixes the problem for you please?

-- 
Mel Gorman
SUSE Labs
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] tmpfs: fix shared mempolicy leak

2012-12-05 Thread Tommi Rantala
2012/12/5 Mel Gorman mgor...@suse.de:
 On Tue, Dec 04, 2012 at 11:24:30PM -0800, Hugh Dickins wrote:
 From: Mel Gorman mgor...@suse.de

 Commit 00442ad04a5e (mempolicy: fix a memory corruption by refcount
 imbalance in alloc_pages_vma()) changed get_vma_policy() to raise the
 refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
 on expecting alloc_page_vma() to drop the refcount it had acquired.
 This deserves a rework: but for now fix the leak in shmem_alloc_page().

 Thanks Hugh for turning gibber into a patch!

 Signed-off-by: Mel Gorman mgor...@suse.de

 Tommi, just in case, can you confirm this fixes the problem for you please?

Confirmed! No more complaints from kmemleak.

Thanks,
Tommi
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] tmpfs: fix shared mempolicy leak

2012-12-05 Thread Hugh Dickins
On Wed, 5 Dec 2012, Tommi Rantala wrote:
 2012/12/5 Mel Gorman mgor...@suse.de:
  On Tue, Dec 04, 2012 at 11:24:30PM -0800, Hugh Dickins wrote:
  From: Mel Gorman mgor...@suse.de
 
  Commit 00442ad04a5e (mempolicy: fix a memory corruption by refcount
  imbalance in alloc_pages_vma()) changed get_vma_policy() to raise the
  refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
  on expecting alloc_page_vma() to drop the refcount it had acquired.
  This deserves a rework: but for now fix the leak in shmem_alloc_page().
 
  Thanks Hugh for turning gibber into a patch!
 
  Signed-off-by: Mel Gorman mgor...@suse.de
 
  Tommi, just in case, can you confirm this fixes the problem for you please?
 
 Confirmed! No more complaints from kmemleak.

Great, thanks.  I'll update the tags and send straight to Linus now.

Hugh
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] tmpfs: fix shared mempolicy leak

2012-12-05 Thread Hugh Dickins
From: Mel Gorman mgor...@suse.de

This fixes a regression in 3.7-rc, which has since gone into stable.

Commit 00442ad04a5e (mempolicy: fix a memory corruption by refcount
imbalance in alloc_pages_vma()) changed get_vma_policy() to raise the
refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
on expecting alloc_page_vma() to drop the refcount it had acquired.
This deserves a rework: but for now fix the leak in shmem_alloc_page().

Hugh: shmem_swapin() did not need a fix, but surely it's clearer to use
the same refcounting there as in shmem_alloc_page(), delete its onstack
mempolicy, and the strange mpol_cond_copy() and __mpol_cond_copy() -
those were invented to let swapin_readahead() make an unknown number of
calls to alloc_pages_vma() with one mempolicy; but since 00442ad04a5e,
alloc_pages_vma() has kept refcount in balance, so now no problem.

Reported-and-tested-by: Tommi Rantala tt.rant...@gmail.com
Signed-off-by: Mel Gorman mgor...@suse.de
Signed-off-by: Hugh Dickins hu...@google.com
Cc: sta...@vger.kernel.org
---

 include/linux/mempolicy.h |   16 
 mm/mempolicy.c|   22 --
 mm/shmem.c|   26 --
 3 files changed, 16 insertions(+), 48 deletions(-)

--- 3.7-rc8/include/linux/mempolicy.h   2012-10-14 16:16:57.637308925 -0700
+++ linux/include/linux/mempolicy.h 2012-12-04 22:38:21.812178829 -0800
@@ -82,16 +82,6 @@ static inline void mpol_cond_put(struct
__mpol_put(pol);
 }
 
-extern struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
- struct mempolicy *frompol);
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *tompol,
-   struct mempolicy *frompol)
-{
-   if (!frompol)
-   return frompol;
-   return __mpol_cond_copy(tompol, frompol);
-}
-
 extern struct mempolicy *__mpol_dup(struct mempolicy *pol);
 static inline struct mempolicy *mpol_dup(struct mempolicy *pol)
 {
@@ -215,12 +205,6 @@ static inline void mpol_cond_put(struct
 {
 }
 
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *to,
-   struct mempolicy *from)
-{
-   return from;
-}
-
 static inline void mpol_get(struct mempolicy *pol)
 {
 }
--- 3078/mm/mempolicy.c 2012-10-20 20:56:24.675917367 -0700
+++ 3078X/mm/mempolicy.c2012-12-04 22:33:31.516171929 -0800
@@ -2037,28 +2037,6 @@ struct mempolicy *__mpol_dup(struct memp
return new;
 }
 
-/*
- * If *frompol needs [has] an extra ref, copy *frompol to *tompol ,
- * eliminate the * MPOL_F_* flags that require conditional ref and
- * [NOTE!!!] drop the extra ref.  Not safe to reference *frompol directly
- * after return.  Use the returned value.
- *
- * Allows use of a mempolicy for, e.g., multiple allocations with a single
- * policy lookup, even if the policy needs/has extra ref on lookup.
- * shmem_readahead needs this.
- */
-struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
-   struct mempolicy *frompol)
-{
-   if (!mpol_needs_cond_ref(frompol))
-   return frompol;
-
-   *tompol = *frompol;
-   tompol-flags = ~MPOL_F_SHARED;/* copy doesn't need unref */
-   __mpol_put(frompol);
-   return tompol;
-}
-
 /* Slow path of a mempolicy comparison */
 bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
 {
--- 3078/mm/shmem.c 2012-11-16 19:26:56.388459961 -0800
+++ 3078X/mm/shmem.c2012-12-04 22:32:35.328170594 -0800
@@ -910,25 +910,29 @@ static struct mempolicy *shmem_get_sbmpo
 static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
 {
-   struct mempolicy mpol, *spol;
struct vm_area_struct pvma;
-
-   spol = mpol_cond_copy(mpol,
-   mpol_shared_policy_lookup(info-policy, index));
+   struct page *page;
 
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
/* Bias interleave by inode number to distribute better across nodes */
pvma.vm_pgoff = index + info-vfs_inode.i_ino;
pvma.vm_ops = NULL;
-   pvma.vm_policy = spol;
-   return swapin_readahead(swap, gfp, pvma, 0);
+   pvma.vm_policy = mpol_shared_policy_lookup(info-policy, index);
+
+   page = swapin_readahead(swap, gfp, pvma, 0);
+
+   /* Drop reference taken by mpol_shared_policy_lookup() */
+   mpol_cond_put(pvma.vm_policy);
+
+   return page;
 }
 
 static struct page *shmem_alloc_page(gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
 {
struct vm_area_struct pvma;
+   struct page *page;
 
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
@@ -937,10 +941,12 @@ static struct page *shmem_alloc_page(gfp
pvma.vm_ops = 

[PATCH] tmpfs: fix shared mempolicy leak

2012-12-04 Thread Hugh Dickins
From: Mel Gorman 

Commit 00442ad04a5e ("mempolicy: fix a memory corruption by refcount
imbalance in alloc_pages_vma()") changed get_vma_policy() to raise the
refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
on expecting alloc_page_vma() to drop the refcount it had acquired.
This deserves a rework: but for now fix the leak in shmem_alloc_page().

Hugh: shmem_swapin() did not need a fix, but surely it's clearer to use
the same refcounting there as in shmem_alloc_page(), delete its onstack
mempolicy, and the strange mpol_cond_copy() and __mpol_cond_copy() -
those were invented to let swapin_readahead() make an unknown number of
calls to alloc_pages_vma() with one mempolicy; but since 00442ad04a5e,
alloc_pages_vma() has kept refcount in balance, so now no problem.

Reported-by: Tommi Rantala 
Awaiting-signed-off-by: Mel Gorman 
Signed-off-by: Hugh Dickins 
Cc: sta...@vger.kernel.org
---

 include/linux/mempolicy.h |   16 
 mm/mempolicy.c|   22 --
 mm/shmem.c|   26 --
 3 files changed, 16 insertions(+), 48 deletions(-)

--- 3.7-rc8/include/linux/mempolicy.h   2012-10-14 16:16:57.637308925 -0700
+++ linux/include/linux/mempolicy.h 2012-12-04 22:38:21.812178829 -0800
@@ -82,16 +82,6 @@ static inline void mpol_cond_put(struct
__mpol_put(pol);
 }
 
-extern struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
- struct mempolicy *frompol);
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *tompol,
-   struct mempolicy *frompol)
-{
-   if (!frompol)
-   return frompol;
-   return __mpol_cond_copy(tompol, frompol);
-}
-
 extern struct mempolicy *__mpol_dup(struct mempolicy *pol);
 static inline struct mempolicy *mpol_dup(struct mempolicy *pol)
 {
@@ -215,12 +205,6 @@ static inline void mpol_cond_put(struct
 {
 }
 
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *to,
-   struct mempolicy *from)
-{
-   return from;
-}
-
 static inline void mpol_get(struct mempolicy *pol)
 {
 }
--- 3078/mm/mempolicy.c 2012-10-20 20:56:24.675917367 -0700
+++ 3078X/mm/mempolicy.c2012-12-04 22:33:31.516171929 -0800
@@ -2037,28 +2037,6 @@ struct mempolicy *__mpol_dup(struct memp
return new;
 }
 
-/*
- * If *frompol needs [has] an extra ref, copy *frompol to *tompol ,
- * eliminate the * MPOL_F_* flags that require conditional ref and
- * [NOTE!!!] drop the extra ref.  Not safe to reference *frompol directly
- * after return.  Use the returned value.
- *
- * Allows use of a mempolicy for, e.g., multiple allocations with a single
- * policy lookup, even if the policy needs/has extra ref on lookup.
- * shmem_readahead needs this.
- */
-struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
-   struct mempolicy *frompol)
-{
-   if (!mpol_needs_cond_ref(frompol))
-   return frompol;
-
-   *tompol = *frompol;
-   tompol->flags &= ~MPOL_F_SHARED;/* copy doesn't need unref */
-   __mpol_put(frompol);
-   return tompol;
-}
-
 /* Slow path of a mempolicy comparison */
 bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
 {
--- 3078/mm/shmem.c 2012-11-16 19:26:56.388459961 -0800
+++ 3078X/mm/shmem.c2012-12-04 22:32:35.328170594 -0800
@@ -910,25 +910,29 @@ static struct mempolicy *shmem_get_sbmpo
 static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
 {
-   struct mempolicy mpol, *spol;
struct vm_area_struct pvma;
-
-   spol = mpol_cond_copy(,
-   mpol_shared_policy_lookup(>policy, index));
+   struct page *page;
 
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
/* Bias interleave by inode number to distribute better across nodes */
pvma.vm_pgoff = index + info->vfs_inode.i_ino;
pvma.vm_ops = NULL;
-   pvma.vm_policy = spol;
-   return swapin_readahead(swap, gfp, , 0);
+   pvma.vm_policy = mpol_shared_policy_lookup(>policy, index);
+
+   page = swapin_readahead(swap, gfp, , 0);
+
+   /* Drop reference taken by mpol_shared_policy_lookup() */
+   mpol_cond_put(pvma.vm_policy);
+
+   return page;
 }
 
 static struct page *shmem_alloc_page(gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
 {
struct vm_area_struct pvma;
+   struct page *page;
 
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
@@ -937,10 +941,12 @@ static struct page *shmem_alloc_page(gfp
pvma.vm_ops = NULL;
pvma.vm_policy = mpol_shared_policy_lookup(>policy, index);
 
-   /*
-* alloc_page_vma() will drop the shared policy reference
-

[PATCH] tmpfs: fix shared mempolicy leak

2012-12-04 Thread Hugh Dickins
From: Mel Gorman mgor...@suse.de

Commit 00442ad04a5e (mempolicy: fix a memory corruption by refcount
imbalance in alloc_pages_vma()) changed get_vma_policy() to raise the
refcount on a shmem shared mempolicy; whereas shmem_alloc_page() went
on expecting alloc_page_vma() to drop the refcount it had acquired.
This deserves a rework: but for now fix the leak in shmem_alloc_page().

Hugh: shmem_swapin() did not need a fix, but surely it's clearer to use
the same refcounting there as in shmem_alloc_page(), delete its onstack
mempolicy, and the strange mpol_cond_copy() and __mpol_cond_copy() -
those were invented to let swapin_readahead() make an unknown number of
calls to alloc_pages_vma() with one mempolicy; but since 00442ad04a5e,
alloc_pages_vma() has kept refcount in balance, so now no problem.

Reported-by: Tommi Rantala tt.rant...@gmail.com
Awaiting-signed-off-by: Mel Gorman mgor...@suse.de
Signed-off-by: Hugh Dickins hu...@google.com
Cc: sta...@vger.kernel.org
---

 include/linux/mempolicy.h |   16 
 mm/mempolicy.c|   22 --
 mm/shmem.c|   26 --
 3 files changed, 16 insertions(+), 48 deletions(-)

--- 3.7-rc8/include/linux/mempolicy.h   2012-10-14 16:16:57.637308925 -0700
+++ linux/include/linux/mempolicy.h 2012-12-04 22:38:21.812178829 -0800
@@ -82,16 +82,6 @@ static inline void mpol_cond_put(struct
__mpol_put(pol);
 }
 
-extern struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
- struct mempolicy *frompol);
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *tompol,
-   struct mempolicy *frompol)
-{
-   if (!frompol)
-   return frompol;
-   return __mpol_cond_copy(tompol, frompol);
-}
-
 extern struct mempolicy *__mpol_dup(struct mempolicy *pol);
 static inline struct mempolicy *mpol_dup(struct mempolicy *pol)
 {
@@ -215,12 +205,6 @@ static inline void mpol_cond_put(struct
 {
 }
 
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *to,
-   struct mempolicy *from)
-{
-   return from;
-}
-
 static inline void mpol_get(struct mempolicy *pol)
 {
 }
--- 3078/mm/mempolicy.c 2012-10-20 20:56:24.675917367 -0700
+++ 3078X/mm/mempolicy.c2012-12-04 22:33:31.516171929 -0800
@@ -2037,28 +2037,6 @@ struct mempolicy *__mpol_dup(struct memp
return new;
 }
 
-/*
- * If *frompol needs [has] an extra ref, copy *frompol to *tompol ,
- * eliminate the * MPOL_F_* flags that require conditional ref and
- * [NOTE!!!] drop the extra ref.  Not safe to reference *frompol directly
- * after return.  Use the returned value.
- *
- * Allows use of a mempolicy for, e.g., multiple allocations with a single
- * policy lookup, even if the policy needs/has extra ref on lookup.
- * shmem_readahead needs this.
- */
-struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
-   struct mempolicy *frompol)
-{
-   if (!mpol_needs_cond_ref(frompol))
-   return frompol;
-
-   *tompol = *frompol;
-   tompol-flags = ~MPOL_F_SHARED;/* copy doesn't need unref */
-   __mpol_put(frompol);
-   return tompol;
-}
-
 /* Slow path of a mempolicy comparison */
 bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
 {
--- 3078/mm/shmem.c 2012-11-16 19:26:56.388459961 -0800
+++ 3078X/mm/shmem.c2012-12-04 22:32:35.328170594 -0800
@@ -910,25 +910,29 @@ static struct mempolicy *shmem_get_sbmpo
 static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
 {
-   struct mempolicy mpol, *spol;
struct vm_area_struct pvma;
-
-   spol = mpol_cond_copy(mpol,
-   mpol_shared_policy_lookup(info-policy, index));
+   struct page *page;
 
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
/* Bias interleave by inode number to distribute better across nodes */
pvma.vm_pgoff = index + info-vfs_inode.i_ino;
pvma.vm_ops = NULL;
-   pvma.vm_policy = spol;
-   return swapin_readahead(swap, gfp, pvma, 0);
+   pvma.vm_policy = mpol_shared_policy_lookup(info-policy, index);
+
+   page = swapin_readahead(swap, gfp, pvma, 0);
+
+   /* Drop reference taken by mpol_shared_policy_lookup() */
+   mpol_cond_put(pvma.vm_policy);
+
+   return page;
 }
 
 static struct page *shmem_alloc_page(gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
 {
struct vm_area_struct pvma;
+   struct page *page;
 
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
@@ -937,10 +941,12 @@ static struct page *shmem_alloc_page(gfp
pvma.vm_ops = NULL;
pvma.vm_policy = mpol_shared_policy_lookup(info-policy,