aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
authorMel Gorman <mgorman@suse.de>2012-12-05 17:01:41 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-06 14:56:43 -0500
commit18a2f371f5edf41810f6469cb9be39931ef9deb9 (patch)
tree4e4ec26f13273b36fc7203d2084ea09f14c5f0f7 /mm/shmem.c
parentc702418f8a2fa6cc92e84a39880d458faf7af9cc (diff)
tmpfs: fix shared mempolicy leak
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.rantala@gmail.com> Signed-off-by: Mel Gorman <mgorman@suse.de> Signed-off-by: Hugh Dickins <hughd@google.com> Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index 89341b658bd0..50c5b8f3a359 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -910,25 +910,29 @@ static struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo)
910static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp, 910static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
911 struct shmem_inode_info *info, pgoff_t index) 911 struct shmem_inode_info *info, pgoff_t index)
912{ 912{
913 struct mempolicy mpol, *spol;
914 struct vm_area_struct pvma; 913 struct vm_area_struct pvma;
915 914 struct page *page;
916 spol = mpol_cond_copy(&mpol,
917 mpol_shared_policy_lookup(&info->policy, index));
918 915
919 /* Create a pseudo vma that just contains the policy */ 916 /* Create a pseudo vma that just contains the policy */
920 pvma.vm_start = 0; 917 pvma.vm_start = 0;
921 /* Bias interleave by inode number to distribute better across nodes */ 918 /* Bias interleave by inode number to distribute better across nodes */
922 pvma.vm_pgoff = index + info->vfs_inode.i_ino; 919 pvma.vm_pgoff = index + info->vfs_inode.i_ino;
923 pvma.vm_ops = NULL; 920 pvma.vm_ops = NULL;
924 pvma.vm_policy = spol; 921 pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
925 return swapin_readahead(swap, gfp, &pvma, 0); 922
923 page = swapin_readahead(swap, gfp, &pvma, 0);
924
925 /* Drop reference taken by mpol_shared_policy_lookup() */
926 mpol_cond_put(pvma.vm_policy);
927
928 return page;
926} 929}
927 930
928static struct page *shmem_alloc_page(gfp_t gfp, 931static struct page *shmem_alloc_page(gfp_t gfp,
929 struct shmem_inode_info *info, pgoff_t index) 932 struct shmem_inode_info *info, pgoff_t index)
930{ 933{
931 struct vm_area_struct pvma; 934 struct vm_area_struct pvma;
935 struct page *page;
932 936
933 /* Create a pseudo vma that just contains the policy */ 937 /* Create a pseudo vma that just contains the policy */
934 pvma.vm_start = 0; 938 pvma.vm_start = 0;
@@ -937,10 +941,12 @@ static struct page *shmem_alloc_page(gfp_t gfp,
937 pvma.vm_ops = NULL; 941 pvma.vm_ops = NULL;
938 pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index); 942 pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
939 943
940 /* 944 page = alloc_page_vma(gfp, &pvma, 0);
941 * alloc_page_vma() will drop the shared policy reference 945
942 */ 946 /* Drop reference taken by mpol_shared_policy_lookup() */
943 return alloc_page_vma(gfp, &pvma, 0); 947 mpol_cond_put(pvma.vm_policy);
948
949 return page;
944} 950}
945#else /* !CONFIG_NUMA */ 951#else /* !CONFIG_NUMA */
946#ifdef CONFIG_TMPFS 952#ifdef CONFIG_TMPFS