Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Mel Gorman and committed by
Linus Torvalds
18a2f371 c702418f

+28 -60
-16
include/linux/mempolicy.h
··· 82 82 __mpol_put(pol); 83 83 } 84 84 85 - extern struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol, 86 - struct mempolicy *frompol); 87 - static inline struct mempolicy *mpol_cond_copy(struct mempolicy *tompol, 88 - struct mempolicy *frompol) 89 - { 90 - if (!frompol) 91 - return frompol; 92 - return __mpol_cond_copy(tompol, frompol); 93 - } 94 - 95 85 extern struct mempolicy *__mpol_dup(struct mempolicy *pol); 96 86 static inline struct mempolicy *mpol_dup(struct mempolicy *pol) 97 87 { ··· 203 213 204 214 static inline void mpol_cond_put(struct mempolicy *pol) 205 215 { 206 - } 207 - 208 - static inline struct mempolicy *mpol_cond_copy(struct mempolicy *to, 209 - struct mempolicy *from) 210 - { 211 - return from; 212 216 } 213 217 214 218 static inline void mpol_get(struct mempolicy *pol)
-22
mm/mempolicy.c
··· 2037 2037 return new; 2038 2038 } 2039 2039 2040 - /* 2041 - * If *frompol needs [has] an extra ref, copy *frompol to *tompol , 2042 - * eliminate the * MPOL_F_* flags that require conditional ref and 2043 - * [NOTE!!!] drop the extra ref. Not safe to reference *frompol directly 2044 - * after return. Use the returned value. 2045 - * 2046 - * Allows use of a mempolicy for, e.g., multiple allocations with a single 2047 - * policy lookup, even if the policy needs/has extra ref on lookup. 2048 - * shmem_readahead needs this. 2049 - */ 2050 - struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol, 2051 - struct mempolicy *frompol) 2052 - { 2053 - if (!mpol_needs_cond_ref(frompol)) 2054 - return frompol; 2055 - 2056 - *tompol = *frompol; 2057 - tompol->flags &= ~MPOL_F_SHARED; /* copy doesn't need unref */ 2058 - __mpol_put(frompol); 2059 - return tompol; 2060 - } 2061 - 2062 2040 /* Slow path of a mempolicy comparison */ 2063 2041 bool __mpol_equal(struct mempolicy *a, struct mempolicy *b) 2064 2042 {
+28 -22
mm/shmem.c
··· 910 910 static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp, 911 911 struct shmem_inode_info *info, pgoff_t index) 912 912 { 913 - struct mempolicy mpol, *spol; 914 913 struct vm_area_struct pvma; 915 - 916 - spol = mpol_cond_copy(&mpol, 917 - mpol_shared_policy_lookup(&info->policy, index)); 918 - 919 - /* Create a pseudo vma that just contains the policy */ 920 - pvma.vm_start = 0; 921 - /* Bias interleave by inode number to distribute better across nodes */ 922 - pvma.vm_pgoff = index + info->vfs_inode.i_ino; 923 - pvma.vm_ops = NULL; 924 - pvma.vm_policy = spol; 925 - return swapin_readahead(swap, gfp, &pvma, 0); 926 - } 927 - 928 - static struct page *shmem_alloc_page(gfp_t gfp, 929 - struct shmem_inode_info *info, pgoff_t index) 930 - { 931 - struct vm_area_struct pvma; 914 + struct page *page; 932 915 933 916 /* Create a pseudo vma that just contains the policy */ 934 917 pvma.vm_start = 0; ··· 920 937 pvma.vm_ops = NULL; 921 938 pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index); 922 939 923 - /* 924 - * alloc_page_vma() will drop the shared policy reference 925 - */ 926 - return alloc_page_vma(gfp, &pvma, 0); 940 + page = swapin_readahead(swap, gfp, &pvma, 0); 941 + 942 + /* Drop reference taken by mpol_shared_policy_lookup() */ 943 + mpol_cond_put(pvma.vm_policy); 944 + 945 + return page; 946 + } 947 + 948 + static struct page *shmem_alloc_page(gfp_t gfp, 949 + struct shmem_inode_info *info, pgoff_t index) 950 + { 951 + struct vm_area_struct pvma; 952 + struct page *page; 953 + 954 + /* Create a pseudo vma that just contains the policy */ 955 + pvma.vm_start = 0; 956 + /* Bias interleave by inode number to distribute better across nodes */ 957 + pvma.vm_pgoff = index + info->vfs_inode.i_ino; 958 + pvma.vm_ops = NULL; 959 + pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index); 960 + 961 + page = alloc_page_vma(gfp, &pvma, 0); 962 + 963 + /* Drop reference taken by mpol_shared_policy_lookup() */ 964 + mpol_cond_put(pvma.vm_policy); 965 + 966 + return page; 927 967 } 928 968 #else /* !CONFIG_NUMA */ 929 969 #ifdef CONFIG_TMPFS