aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
authorLee Schermerhorn <lee.schermerhorn@hp.com>2008-04-28 05:13:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:24 -0400
commit52cd3b074050dd664380b5e8cfc85d4a6ed8ad48 (patch)
treefcfcf55c0e81376ea34919fab26e29bedd7f3b88 /mm/shmem.c
parenta6020ed759404372e8be2b276e85e51735472cc9 (diff)
mempolicy: rework mempolicy Reference Counting [yet again]
After further discussion with Christoph Lameter, it has become clear that my earlier attempts to clean up the mempolicy reference counting were a bit of overkill in some areas, resulting in superflous ref/unref in what are usually fast paths. In other areas, further inspection reveals that I botched the unref for interleave policies. A separate patch, suitable for upstream/stable trees, fixes up the known errors in the previous attempt to fix reference counting. This patch reworks the memory policy referencing counting and, one hopes, simplifies the code. Maybe I'll get it right this time. See the update to the numa_memory_policy.txt document for a discussion of memory policy reference counting that motivates this patch. Summary: Lookup of mempolicy, based on (vma, address) need only add a reference for shared policy, and we need only unref the policy when finished for shared policies. So, this patch backs out all of the unneeded extra reference counting added by my previous attempt. It then unrefs only shared policies when we're finished with them, using the mpol_cond_put() [conditional put] helper function introduced by this patch. Note that shmem_swapin() calls read_swap_cache_async() with a dummy vma containing just the policy. read_swap_cache_async() can call alloc_page_vma() multiple times, so we can't let alloc_page_vma() unref the shared policy in this case. To avoid this, we make a copy of any non-null shared policy and remove the MPOL_F_SHARED flag from the copy. This copy occurs before reading a page [or multiple pages] from swap, so the overhead should not be an issue here. I introduced a new static inline function "mpol_cond_copy()" to copy the shared policy to an on-stack policy and remove the flags that would require a conditional free. The current implementation of mpol_cond_copy() assumes that the struct mempolicy contains no pointers to dynamically allocated structures that must be duplicated or reference counted during copy. Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com> Cc: Christoph Lameter <clameter@sgi.com> Cc: David Rientjes <rientjes@google.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index 5326876d814d..0b591c669b2d 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1187,16 +1187,19 @@ static void shmem_show_mpol(struct seq_file *seq, unsigned short policy,
1187static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp, 1187static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
1188 struct shmem_inode_info *info, unsigned long idx) 1188 struct shmem_inode_info *info, unsigned long idx)
1189{ 1189{
1190 struct mempolicy mpol, *spol;
1190 struct vm_area_struct pvma; 1191 struct vm_area_struct pvma;
1191 struct page *page; 1192 struct page *page;
1192 1193
1194 spol = mpol_cond_copy(&mpol,
1195 mpol_shared_policy_lookup(&info->policy, idx));
1196
1193 /* Create a pseudo vma that just contains the policy */ 1197 /* Create a pseudo vma that just contains the policy */
1194 pvma.vm_start = 0; 1198 pvma.vm_start = 0;
1195 pvma.vm_pgoff = idx; 1199 pvma.vm_pgoff = idx;
1196 pvma.vm_ops = NULL; 1200 pvma.vm_ops = NULL;
1197 pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx); 1201 pvma.vm_policy = spol;
1198 page = swapin_readahead(entry, gfp, &pvma, 0); 1202 page = swapin_readahead(entry, gfp, &pvma, 0);
1199 mpol_put(pvma.vm_policy);
1200 return page; 1203 return page;
1201} 1204}
1202 1205
@@ -1204,16 +1207,17 @@ static struct page *shmem_alloc_page(gfp_t gfp,
1204 struct shmem_inode_info *info, unsigned long idx) 1207 struct shmem_inode_info *info, unsigned long idx)
1205{ 1208{
1206 struct vm_area_struct pvma; 1209 struct vm_area_struct pvma;
1207 struct page *page;
1208 1210
1209 /* Create a pseudo vma that just contains the policy */ 1211 /* Create a pseudo vma that just contains the policy */
1210 pvma.vm_start = 0; 1212 pvma.vm_start = 0;
1211 pvma.vm_pgoff = idx; 1213 pvma.vm_pgoff = idx;
1212 pvma.vm_ops = NULL; 1214 pvma.vm_ops = NULL;
1213 pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx); 1215 pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
1214 page = alloc_page_vma(gfp, &pvma, 0); 1216
1215 mpol_put(pvma.vm_policy); 1217 /*
1216 return page; 1218 * alloc_page_vma() will drop the shared policy reference
1219 */
1220 return alloc_page_vma(gfp, &pvma, 0);
1217} 1221}
1218#else /* !CONFIG_NUMA */ 1222#else /* !CONFIG_NUMA */
1219#ifdef CONFIG_TMPFS 1223#ifdef CONFIG_TMPFS